﻿/**
* @class ScrollLine2DChart
* @author InfoSoft Global (P) Ltd. www.InfoSoftGlobal.com
* @version 3.0
*
* Copyright (C) InfoSoft Global Pvt. Ltd. 2005-2006
*
* ScrollLine2DChart chart extends the ScrollSingleYAxis2DVerticalChart class to render a
* Scroll 2D Line Chart.
*/
//Import Chart class
import com.fusioncharts.core.Chart;
//Scroll Bar
import com.fusioncharts.helper.FCHScrollPane;
//Parent SingleYAxis2DVerticalChart Class
import com.fusioncharts.core.ScrollSingleYAxis2DVerticalChart;
//Error class
import com.fusioncharts.helper.FCError;
//Import Logger Class
import com.fusioncharts.helper.Logger;
//Style Object
import com.fusioncharts.core.StyleObject;
//Delegate
import mx.utils.Delegate;
//Legend Class
import com.fusioncharts.helper.Legend;
//Extensions
import com.fusioncharts.extensions.ColorExt;
import com.fusioncharts.extensions.StringExt;
import com.fusioncharts.extensions.MathExt;
import com.fusioncharts.extensions.DrawingExt;
class com.fusioncharts.core.charts.ScrollLine2DChart extends ScrollSingleYAxis2DVerticalChart {
	//Version number (if different from super Chart class)
	//private var _version:String = "3.0.0";
	//Instance variables
	//List of chart objects
	private var _arrObjects:Array;
	private var xmlData:XML;
	//Array to store x-axis categories (labels)
	private var categories:Array;
	//Array to store datasets
	private var dataset:Array;
	//Number of data sets
	private var numDS:Number;
	//Number of data items
	private var num:Number;
	//Reference to legend component of chart
	private var lgnd:Legend;
	//Reference to legend movie clip
	private var lgndMC:MovieClip;
	//Masking MovieClip
	private var maskMC:MovieClip;
	//ScrollPane MC
	private var scrollMC:MovieClip;
	//Scroll Bar
	private var scrollBar:FCHScrollPane;
	private var canvasMC:MovieClip;
	private var textCanvasMC:MovieClip;
	private var drawCanvasMC:MovieClip;
	private var scrollHeight:Number = 20;
	/**
	* Constructor function. We invoke the super class'
	* constructor and then set the objects for this chart.
	*/
	function ScrollLine2DChart(targetMC:MovieClip, depth:Number, width:Number, height:Number, x:Number, y:Number, debugMode:Boolean, lang:String) {
		//Invoke the super class constructor
		super(targetMC, depth, width, height, x, y, debugMode, lang);
		//Log additional information to debugger
		//We log version from this class, so that if this class version
		//is different, we can log it
		this.log("Version", _version, Logger.LEVEL.INFO);
		this.log("Chart Type", "Scroll 2D Line Chart", Logger.LEVEL.INFO);
		//List Chart Objects and set them
		_arrObjects = new Array("BACKGROUND", "CANVAS", "CAPTION", "SUBCAPTION", "YAXISNAME", "XAXISNAME", "DIVLINES", "VDIVLINES", "YAXISVALUES", "HGRID", "VGRID", "DATALABELS", "DATAVALUES", "TRENDLINES", "TRENDVALUES", "SCROLLPANE", "DATAPLOT", "ANCHORS", "TOOLTIP", "VLINES", "LEGEND");
		super.setChartObjects(_arrObjects);
		//Initialize the containers for chart
		this.categories = new Array();
		this.dataset = new Array();
		//Initialize the number of data elements present
		this.numDS = 0;
		this.num = 0;
		//Scroll Flag
		this.config.scrollRequired = false;
	}
	/**
	* render method is the single call method that does the rendering of chart:
	* - Parsing XML
	* - Calculating values and co-ordinates
	* - Visual layout and rendering
	* - Event handling
	*/
	public function render():Void {
		//Parse the XML Data document
		this.parseXML();
		//Now, if the number of data elements is 0, we show pertinent
		//error.
		if (this.numDS*this.num == 0) {
			tfAppMsg = this.renderAppMessage(_global.getAppMessage("NODATA", this.lang));
			//Add a message to log.
			this.log("No Data to Display", "No data was found in the XML data document provided. Possible cases can be: <LI>There isn't any data generated by your system. If your system generates data based on parameters passed to it using dataURL, please make sure dataURL is URL Encoded.</LI><LI>You might be using a Single Series Chart .swf file instead of Multi-series .swf file and providing multi-series data or vice-versa.</LI>", Logger.LEVEL.ERROR);
		} else {
			//Detect number scales
			this.detectNumberScales();
			//Calculate the axis limits
			this.calculateAxisLimits();
			//Calculate exact number of div lines
			this.calcDivs();
			//Set Style defaults
			this.setStyleDefaults();
			//Validate trend lines
			this.validateTrendLines();
			//Allot the depths for various charts objects now
			this.allotCanvasDepths();
			//Allot the depths for various charts objects now
			this.allotDepths();
			//Calculate Points
			this.calculatePoints();
			//Calculate vLine Positions
			this.calcVLinesPos();
			//Calculate trend line positions
			this.calcTrendLinePos();			
			//Feed macro values
			super.feedMacros();
			//Remove application message
			this.removeAppMessage(this.tfAppMsg);
			//Set tool tip parameter
			this.setToolTipParam();
			//-----Start Visual Rendering Now------//
			//Draw background
			this.drawBackground();
			//Set click handler
			this.drawClickURLHandler();
			//Load background SWF
			this.loadBgSWF();
			//Update timer
			this.timeElapsed = (this.params.animation) ? this.styleM.getMaxAnimationTime(this.objects.BACKGROUND) : 0;
			//Draw canvas
			this.config.intervals.canvas = setInterval(Delegate.create(this, drawCanvas), this.timeElapsed);
			//Draw headers
			this.config.intervals.headers = setInterval(Delegate.create(this, drawHeaders), this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime(this.objects.CANVAS, this.objects.CAPTION, this.objects.SUBCAPTION, this.objects.YAXISNAME, this.objects.XAXISNAME) : 0;
			//Draw div lines
			this.config.intervals.divLines = setInterval(Delegate.create(this, drawDivLines), this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime(this.objects.DIVLINES, this.objects.YAXISVALUES) : 0;
			//Vertical div lines
			this.config.intervals.vDivLines = setInterval(Delegate.create(this, drawVDivLines), this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation && (this.params.numVDivLines>0)) ? this.styleM.getMaxAnimationTime(this.objects.VDIVLINES) : 0;
			//Horizontal grid
			this.config.intervals.hGrid = setInterval(Delegate.create(this, drawHGrid), this.timeElapsed);
			//Vertical grid
			this.config.intervals.vGrid = setInterval(Delegate.create(this, drawVGrid), this.timeElapsed);
			//ScrollPane
			this.config.intervals.scrollPane = setInterval(Delegate.create(this, drawScrollPane), this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation && (this.params.showAlternateHGridColor || this.params.showAlternateVGridColor)) ? this.styleM.getMaxAnimationTime(this.objects.HGRID, this.objects.VGRID) : 0;
			//Draw labels
			this.config.intervals.labels = setInterval(Delegate.create(this, drawLabels), this.timeElapsed);
			//Draw line chart
			this.config.intervals.plot = setInterval(Delegate.create(this, drawLineChart), this.timeElapsed);
			//Legend
			this.config.intervals.legend = setInterval(Delegate.create(this, drawLegend), this.timeElapsed);			
			//Update timer
			this.timeElapsed += (this.params.animation && (this.num>1)) ? this.styleM.getMaxAnimationTime(this.objects.DATALABELS, this.objects.DATAPLOT, this.objects.LEGEND) : 0;
			//Data Values
			this.config.intervals.dataValues = setInterval(Delegate.create(this, drawValues), this.timeElapsed);
			//Anchors
			this.config.intervals.anchors = setInterval(Delegate.create(this, drawAnchors), this.timeElapsed);
			//Draw trend lines
			this.config.intervals.trend = setInterval(Delegate.create(this, drawTrendLines), this.timeElapsed);
			//Draw vertical div lines
			this.config.intervals.vLine = setInterval(Delegate.create(this, drawVLines), this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime(this.objects.ANCHORS, this.objects.TRENDLINES, this.objects.TRENDVALUES, this.objects.VLINES, this.objects.DATAVALUES) : 0;
			//ScrollPane
			this.config.intervals.finalizeScrollPane = setInterval(Delegate.create(this, finalizeScrollPane), this.timeElapsed);
			//Render context menu
			//We do not put context menu interval as we need the menu to appear
			//right from start of the play.			
			this.setContextMenu();
		}
	}
	/**
	* returnDataAsObject method creates an object out of the parameters
	* passed to this method. The idea is that we store each data point
	* as an object with multiple (flexible) properties. So, we do not
	* use a predefined class structure. Instead we use a generic object.
	*	@param	value		Value for the data.
	*	@param	color		Hex Color code.
	*	@param	alpha		Alpha of the line
	*	@param	toolText	Tool tip text (if specified).
	*	@param	link		Link (if any) for the data.
	*	@param	showValue	Flag to show/hide value for this data.
	*	@param	isDashed	Flag whether the line would be dashed.
	*	@param	anchorSides				Number of sides of the anchor.
	*	@param	anchorRadius			Radius of the anchor (in pixels).
	*	@param	anchorBorderColor		Border color of the anchor.
	*	@param	anchorBorderThickness	Border thickness of the anchor.
	*	@param	anchorBgColor			Background color of the anchor.
	*	@param	anchorAlpha				Alpha of the anchor.
	*	@param	anchorBgAlpha			Background (fill) alpha of the anchor.
	*	@returns			An object encapsulating all these properies.
	*/
	private function returnDataAsObject(value:Number, color:String, alpha:Number, toolText:String, link:String, showValue:Number, isDashed:Boolean, anchorSides:Number, anchorRadius:Number, anchorBorderColor:String, anchorBorderThickness:Number, anchorBgColor:String, anchorAlpha:Number, anchorBgAlpha:Number):Object {
		//Create a container
		var dataObj:Object = new Object();
		//Store the values
		dataObj.value = value;
		dataObj.color = color;
		dataObj.alpha = alpha;
		dataObj.toolText = toolText;
		dataObj.link = link;
		dataObj.showValue = (showValue == 1) ? true : false;
		dataObj.dashed = isDashed;
		//Anchor properties
		dataObj.anchorSides = anchorSides;
		dataObj.anchorRadius = anchorRadius;
		dataObj.anchorBorderColor = anchorBorderColor;
		dataObj.anchorBorderThickness = anchorBorderThickness;
		dataObj.anchorBgColor = anchorBgColor;
		dataObj.anchorAlpha = anchorAlpha;
		dataObj.anchorBgAlpha = anchorBgAlpha;
		//If the given number is not a valid number or it's missing
		//set appropriate flags for this data point
		dataObj.isDefined = ((dataObj.alpha == 0) || isNaN(value)) ? false : true;
		//Other parameters
		//X & Y Position of data point
		dataObj.x = 0;
		dataObj.y = 0;
		//X & Y Position of value tb
		dataObj.valTBX = 0;
		dataObj.valTBY = 0;
		//Return the container
		return dataObj;
	}
	/**
	 * returnDataAsCat method returns data of a <category> element as
	 * an object
	 *	@param	label		Label of the category.
	 *	@param	showLabel	Whether to show the label of this category.
	 *	@param	toolText	Tool-text for the category
	 *	@returns			A container object with the given properties
	*/
	private function returnDataAsCat(label:String, showLabel:Number, toolText:String):Object{
		//Create container object
		var catObj:Object = new Object();
		catObj.label = label;
		catObj.showLabel = ((showLabel == 1) && (label!=undefined) && (label!=null) && (label!="")) ? true : false;
		catObj.toolText = toolText;
		//X and Y Position
		catObj.x = 0;
		catObj.y = 0;
		//Return container
		return catObj;
	}
	/**
	* parseXML method parses the XML data, sets defaults and validates
	* the attributes before storing them to data storage objects.
	*/
	private function parseXML():Void {
		//Get the element nodes
		var arrDocElement:Array = this.xmlData.childNodes;
		//Loop variable
		var i:Number;
		var j:Number;
		var k:Number;
		//Look for <graph> element
		for (i=0; i<arrDocElement.length; i++) {
			//If it's a <graph> element, proceed.
			//Do case in-sensitive mathcing by changing to upper case
			if (arrDocElement[i].nodeName.toUpperCase() == "GRAPH" || arrDocElement[i].nodeName.toUpperCase() == "CHART") {
				//Extract attributes of <graph> element
				this.parseAttributes(arrDocElement[i]);
				//Now, get the child nodes - first level nodes
				//Level 1 nodes can be - CATEGORIES, DATASET, TRENDLINES, STYLES etc.
				var arrLevel1Nodes:Array = arrDocElement[i].childNodes;
				var setNode:XMLNode;
				//Iterate through all level 1 nodes.
				for (j=0; j<arrLevel1Nodes.length; j++) {
					if (arrLevel1Nodes[j].nodeName.toUpperCase() == "CATEGORIES") {
						//Categories Node. 
						var categoriesNode:XMLNode = arrLevel1Nodes[j];
						//Convert attributes to array
						var categoriesAtt:Array = this.getAttributesArray(categoriesNode);
						//Extract attributes of this node.
						this.params.catFont = getFV(categoriesAtt["font"],this.params.outCnvBaseFont);
						this.params.catFontSize = getFN(categoriesAtt["fontsize"],this.params.outCnvBaseFontSize);
						this.params.catFontColor = formatColor(getFV(categoriesAtt["fontcolor"],this.params.outCnvBaseFontColor));
						//Get reference to child node.
						var arrLevel2Nodes:Array = arrLevel1Nodes[j].childNodes;
						//Iterate through all child-nodes of CATEGORIES element
						//and search for CATEGORY or VLINE node
						for (k=0; k<arrLevel2Nodes.length; k++){
							if (arrLevel2Nodes[k].nodeName.toUpperCase() == "CATEGORY"){
								//Category Node. 
								//Update counter
								this.num++;
								//Extract attributes
								var categoryNode:XMLNode = arrLevel2Nodes[k];
								var categoryAtt:Array = this.getAttributesArray(categoryNode);
								//Category label.
								var catLabel:String = getFV(categoryAtt["label"], categoryAtt["name"], "");
								var catShowLabel:Number = getFN(categoryAtt["showlabel"], categoryAtt["showname"], this.params.showLabels);
								var catToolText:String = getFV(categoryAtt["tooltext"], categoryAtt["hovertext"], catLabel);
								//Store it in data container.
								this.categories[this.num] = this.returnDataAsCat(catLabel, catShowLabel, catToolText);
							}
							else if (arrLevel2Nodes[k].nodeName.toUpperCase() == "VLINE") {
								//Vertical axis division Node - extract child nodes
								var vLineNode:XMLNode = arrLevel2Nodes[k];
								//Parse and store
								this.parseVLineNode(vLineNode, this.num);
							}
						}						
					} else if (arrLevel1Nodes[j].nodeName.toUpperCase() == "DATASET") {
						//Increment
						this.numDS++;
						//Dataset node.
						var dataSetNode:XMLNode = arrLevel1Nodes[j];
						//Get attributes array
						var dsAtts:Array = this.getAttributesArray(dataSetNode);
						//Create storage object in dataset array
						this.dataset[this.numDS] = new Object();
						//Store attributes
						this.dataset[this.numDS].seriesName = getFV(dsAtts["seriesname"],"");
						this.dataset[this.numDS].color = formatColor(getFV(dsAtts["color"], this.params.lineColor, this.defColors.getColor()));
						this.dataset[this.numDS].alpha = getFN(dsAtts["alpha"], this.params.lineAlpha);
						this.dataset[this.numDS].showValues = toBoolean(getFN(dsAtts["showvalues"], this.params.showValues));						
						this.dataset[this.numDS].includeInLegend = toBoolean(getFN(dsAtts["includeinlegend"], 1));
						//Data set line properties
						this.dataset[this.numDS].lineDashed = toBoolean(getFN(dsAtts["dashed"], this.params.lineDashed));
						//Dash Properties
						this.dataset[this.numDS].lineDashLen = getFN(dsAtts["linedashlen"], this.params.lineDashLen);
						this.dataset[this.numDS].lineDashGap = getFN(dsAtts["linedashgap"], this.params.lineDashGap);				
						this.dataset[this.numDS].lineThickness = getFN(dsAtts["linethickness"], this.params.lineThickness);
						//Data set anchors						
						this.dataset[this.numDS].drawAnchors = toBoolean(getFN(dsAtts["drawanchors"], dsAtts["showanchors"], this.params.drawAnchors));
						this.dataset[this.numDS].anchorSides = getFN(dsAtts["anchorsides"], this.params.anchorSides);
						this.dataset[this.numDS].anchorRadius = getFN(dsAtts["anchorradius"], this.params.anchorRadius);
						this.dataset[this.numDS].anchorBorderColor = formatColor(getFV(dsAtts["anchorbordercolor"], this.params.anchorBorderColor, this.dataset[this.numDS].color));
						this.dataset[this.numDS].anchorBorderThickness = getFN(dsAtts["anchorborderthickness"], this.params.anchorBorderThickness);
						this.dataset[this.numDS].anchorBgColor = formatColor(getFV(dsAtts["anchorbgcolor"], this.params.anchorBgColor));
						this.dataset[this.numDS].anchorAlpha = getFN(dsAtts["anchoralpha"], this.params.anchorAlpha);
						this.dataset[this.numDS].anchorBgAlpha = getFN(dsAtts["anchorbgalpha"], this.params.anchorBgAlpha);		
						//Create data array under it.
						this.dataset[this.numDS].data = new Array();						
						//Get reference to child node.
						var arrLevel2Nodes:Array = arrLevel1Nodes[j].childNodes;
						//Iterate through all child-nodes of DATASET element
						//and search for SET node
						//Counter
						var setCount:Number = 0;
						for (k=0; k<arrLevel2Nodes.length; k++){
							if (arrLevel2Nodes[k].nodeName.toUpperCase() == "SET") {
								//Set Node. So extract the data.
								//Update counter
								setCount++;
								//Get reference to node.
								setNode = arrLevel2Nodes[k];
								//Get attributes
								var atts:Array;
								atts = this.getAttributesArray(setNode);							
								//Now, get value.
								var setValue:Number = this.getSetValue(atts["value"]);
								//We do NOT unescape the link, as this will be done
								//in invokeLink method for the links that user clicks.
								var setLink:String = getFV(atts["link"], "");
								var setToolText:String = getFV(atts["tooltext"], atts["hovertext"]);							
								var setColor:String = formatColor(getFV(atts["color"], this.dataset[this.numDS].color));
								var setAlpha:Number =	getFN(atts["alpha"], this.dataset[this.numDS].alpha);
								var setShowValue:Number = getFN(atts["showvalue"], this.dataset[this.numDS].showValues);
								var setDashed:Boolean = toBoolean(getFN(atts["dashed"], this.dataset[this.numDS].lineDashed));								
								//Anchor properties for individual set
								var setAnchorSides:Number = getFN(atts["anchorsides"], this.dataset[this.numDS].anchorSides);
								var setAnchorRadius:Number = getFN(atts["anchorradius"], this.dataset[this.numDS].anchorRadius);
								var setAnchorBorderColor:String = formatColor(getFV(atts["anchorbordercolor"], this.dataset[this.numDS].anchorBorderColor));
								var setAnchorBorderThickness:Number = getFN(atts["anchorborderthickness"], this.dataset[this.numDS].anchorBorderThickness);
								var setAnchorBgColor:String = formatColor(getFV(atts["anchorbgcolor"], this.dataset[this.numDS].anchorBgColor));
								var setAnchorAlpha:Number = getFN(atts["anchoralpha"], this.dataset[this.numDS].anchorAlpha);
								var setAnchorBgAlpha:Number = getFN(atts["anchorbgalpha"], this.dataset[this.numDS].anchorBgAlpha);						
								//Store all these attributes as object.						
								this.dataset[this.numDS].data[setCount] = this.returnDataAsObject(setValue, setColor, setAlpha, setToolText, setLink, setShowValue, setDashed, setAnchorSides, setAnchorRadius, setAnchorBorderColor, setAnchorBorderThickness, setAnchorBgColor, setAnchorAlpha, setAnchorBgAlpha);
							} 
						}
					} else if (arrLevel1Nodes[j].nodeName.toUpperCase() == "STYLES") {
						//Styles Node - extract child nodes
						var arrStyleNodes:Array = arrLevel1Nodes[j].childNodes;
						//Parse the style nodes to extract style information
						super.parseStyleXML(arrStyleNodes);
					} else if (arrLevel1Nodes[j].nodeName.toUpperCase() == "TRENDLINES") {
						//Trend lines node
						var arrTrendNodes:Array = arrLevel1Nodes[j].childNodes;
						//Parse the trend line nodes
						super.parseTrendLineXML(arrTrendNodes);
					}
				}
			}
		}
		//Delete all temporary objects used for parsing XML Data document
		delete setNode;
		delete arrDocElement;
		delete arrLevel1Nodes;
		delete arrLevel2Nodes;
	}
	/**
	* parseAttributes method parses the attributes and stores them in
	* chart storage objects.
	* Starting ActionScript 2, the parsing of XML attributes have also
	* become case-sensitive. However, prior versions of FusionCharts
	* supported case-insensitive attributes. So we need to parse all
	* attributes as case-insensitive to maintain backward compatibility.
	* To do so, we first extract all attributes from XML, convert it into
	* lower case and then store it in an array. Later, we extract value from
	* this array.
	* @param	graphElement	XML Node containing the <graph> element
	*							and it's attributes
	*/
	private function parseAttributes(graphElement:XMLNode):Void {
		//Array to store the attributes
		var atts:Array = this.getAttributesArray(graphElement);
		//NOW IT'S VERY NECCESARY THAT WHEN WE REFERENCE THIS ARRAY
		//TO GET AN ATTRIBUTE VALUE, WE SHOULD PROVIDE THE ATTRIBUTE
		//NAME IN LOWER CASE. ELSE, UNDEFINED VALUE WOULD SHOW UP.
		//Extract attributes pertinent to this chart
		//Which palette to use?
		this.params.palette = getFN(atts["palette"],1)
		//Whether to show about FusionCharts Menu Item - by default set to on
		this.params.showFCMenuItem = toBoolean(getFN (atts ["showfcmenuitem"] , 1));
		// ---------- PADDING AND SPACING RELATED ATTRIBUTES ----------- //
		//captionPadding = Space between caption/subcaption and canvas start Y
		this.params.captionPadding = getFN(atts["captionpadding"], 10);
		//Canvas Padding is the space between the canvas left/right border
		//and first/last data point
		this.params.canvasPadding = getFN(atts["canvaspadding"], 20);
		//Padding for x-axis name - to the right
		this.params.xAxisNamePadding = getFN(atts["xaxisnamepadding"], 5);
		//Padding for y-axis name - from top
		this.params.yAxisNamePadding = getFN(atts["yaxisnamepadding"], 5);
		//Y-Axis Values padding - Horizontal space between the axis edge and
		//y-axis values or trend line values (on left/right side).
		this.params.yAxisValuesPadding = getFN(atts["yaxisvaluespadding"], 2);
		//Label padding - Vertical space between the labels and canvas end position
		this.params.labelPadding = getFN(atts["labelpadding"], atts["labelspadding"], 3);
		//Value padding - vertical space between the anchors and start of value textboxes
		this.params.valuePadding = getFN(atts["valuepadding"], 2);
		//Padding of legend from right/bottom side of canvas
		this.params.legendPadding = getFN(atts["legendpadding"], 6);
		//Chart Margins - Empty space at the 4 sides
		this.params.chartLeftMargin = getFN(atts["chartleftmargin"], 15);
		this.params.chartRightMargin = getFN(atts["chartrightmargin"], 15);
		this.params.chartTopMargin = getFN(atts["charttopmargin"], 15);
		this.params.chartBottomMargin = getFN(atts["chartbottommargin"], 15);
		// -------------------------- HEADERS ------------------------- //
		//Chart Caption and sub Caption
		this.params.caption = getFV(atts["caption"], "");
		this.params.subCaption = getFV(atts["subcaption"], "");
		//X and Y Axis Name
		this.params.xAxisName = getFV(atts["xaxisname"], "");
		this.params.yAxisName = getFV(atts["yaxisname"], "");
		//Adaptive yMin - if set to true, the y min will be based on the values 
		//provided. It won't be set to 0 in case of all positive values
		this.params.setAdaptiveYMin = toBoolean(getFN(atts["setadaptiveymin"], 0));
		// --------------------- CONFIGURATION ------------------------- //
		//Number of data points to be shown in the viewable area of scroll pane.
		this.params.numVisiblePlot = atts["numvisibleplot"];
		//The upper and lower limits of y and x axis
		this.params.yAxisMinValue = atts["yaxisminvalue"];
		this.params.yAxisMaxValue = atts["yaxismaxvalue"];
		//Whether to set animation for entire chart.
		this.params.animation = toBoolean(getFN(atts["animation"], 1));
		//Whether to set the default chart animation
		this.params.defaultAnimation = toBoolean(getFN(atts["defaultanimation"], 1));
		//Whether null data points are to be connected or left broken
		this.params.connectNullData = toBoolean(getFN(atts["connectnulldata"], 0));
		//Configuration to set whether to show the labels   
		this.params.showLabels = toBoolean(getFN(atts["showlabels"], atts["shownames"], 1));
		//Label Display Mode - WRAP, STAGGER, ROTATE or NONE
		this.params.labelDisplay = getFV(atts["labeldisplay"], "WRAP");
		//Remove spaces and capitalize
		this.params.labelDisplay = StringExt.removeSpaces(this.params.labelDisplay);
		this.params.labelDisplay = this.params.labelDisplay.toUpperCase();
		//Option to show vertical x-axis labels
		this.params.rotateLabels = getFV(atts["rotatelabels"], atts["rotatenames"]);
		//Whether to slant label (if rotated)
		this.params.slantLabels = toBoolean(getFN(atts["slantlabels"], atts["slantlabel"], 0));
		//Angle of rotation based on slanting
		this.config.labelAngle = (this.params.slantLabels == true) ? 315 : 270;
		//If rotateLabels has been explicitly specified, we assign ROTATE value to this.params.labelDisplay
		this.params.labelDisplay = (this.params.rotateLabels == "1") ? "ROTATE" : this.params.labelDisplay;
		//Step value for labels - i.e., show all labels or skip every x label
		this.params.labelStep = int(getFN(atts["labelstep"], 1));
		//Cannot be less than 1
		this.params.labelStep = (this.params.labelStep<1) ? 1 : this.params.labelStep;
		//Number of stagger lines
		this.params.staggerLines = int(getFN(atts["staggerlines"], 2));
		//Cannot be less than 2
		this.params.staggerLines = (this.params.staggerLines<2) ? 2 : this.params.staggerLines;
		//Configuration whether to show data values
		this.params.showValues = toBoolean(getFN(atts["showvalues"], 1));
		//Whether to rotate values
		this.params.rotateValues = toBoolean(getFN(atts["rotatevalues"], 0));
		//Option to show/hide y-axis values
		this.params.showYAxisValues = getFN(atts["showyaxisvalues"], atts["showyaxisvalue"], 1);
		this.params.showLimits = toBoolean(getFN(atts["showlimits"], this.params.showYAxisValues));
		this.params.showDivLineValues = toBoolean(getFN(atts["showdivlinevalue"], atts["showdivlinevalues"], this.params.showYAxisValues));
		//Y-axis value step- i.e., show all y-axis or skip every x(th) value
		this.params.yAxisValuesStep = int(getFN(atts["yaxisvaluesstep"], atts["yaxisvaluestep"], 1));
		//Cannot be less than 1
		this.params.yAxisValuesStep = (this.params.yAxisValuesStep<1) ? 1 : this.params.yAxisValuesStep;
		//Whether to automatically adjust div lines
		this.params.adjustDiv = toBoolean(getFN(atts["adjustdiv"], 1));
		//Whether to rotate y-axis name
		this.params.rotateYAxisName = toBoolean(getFN(atts["rotateyaxisname"], 1));
		//Max width to be alloted to y-axis name - No defaults, as it's calculated later.
		this.params.yAxisNameWidth = atts["yaxisnamewidth"];
		//Click URL
		this.params.clickURL = getFV(atts["clickurl"], "");
		// ------------------------- COSMETICS -----------------------------//
		//Background properties - Gradient
		this.params.bgColor = getFV(atts["bgcolor"], this.defColors.get2DBgColor(this.params.palette));
		this.params.bgAlpha = getFV(atts["bgalpha"], this.defColors.get2DBgAlpha(this.params.palette));
		this.params.bgRatio = getFV(atts["bgratio"], this.defColors.get2DBgRatio(this.params.palette));
		this.params.bgAngle = getFV(atts["bgangle"], this.defColors.get2DBgAngle(this.params.palette));
		//Border Properties of chart
		this.params.showBorder = toBoolean(getFN(atts["showborder"], 1));
		this.params.borderColor = formatColor(getFV(atts["bordercolor"], this.defColors.get2DBorderColor(this.params.palette)));
		this.params.borderThickness = getFN(atts["borderthickness"], 1);
		this.params.borderAlpha = getFN(atts["borderalpha"], this.defColors.get2DBorderAlpha(this.params.palette));
		//Background swf
		this.params.bgSWF = getFV(atts["bgswf"], "");
		this.params.bgSWFAlpha = getFN(atts["bgswfalpha"], 100);		
		//ScrollColor
		this.params.scrollColor = formatColor(getFV(atts["scrollcolor"], "CCCCCC"));
		//Canvas background properties - Gradient
		this.params.canvasBgColor = getFV(atts["canvasbgcolor"], this.defColors.get2DCanvasBgColor(this.params.palette));
		this.params.canvasBgAlpha = getFV(atts["canvasbgalpha"], this.defColors.get2DCanvasBgAlpha(this.params.palette));
		this.params.canvasBgRatio = getFV(atts["canvasbgratio"], this.defColors.get2DCanvasBgRatio(this.params.palette));
		this.params.canvasBgAngle = getFV(atts["canvasbgangle"], this.defColors.get2DCanvasBgAngle(this.params.palette));
		//Canvas Border properties
		this.params.canvasBorderColor = formatColor(getFV(atts["canvasbordercolor"], this.defColors.get2DCanvasBorderColor(this.params.palette)));
		this.params.canvasBorderThickness = getFN(atts["canvasborderthickness"], 2);
		this.params.canvasBorderAlpha = getFN(atts["canvasborderalpha"], this.defColors.get2DCanvasBorderAlpha(this.params.palette));
		//Line Properties
		this.params.lineColor = atts["linecolor"];
		this.params.lineThickness = getFN(atts["linethickness"], 2);
		this.params.lineAlpha = getFN(atts["linealpha"], 100);
		//Plot is dashed
		this.params.lineDashed = toBoolean(getFN(atts["linedashed"], 0));
		//Dash Properties
		this.params.lineDashLen = getFN(atts["linedashlen"], 5);
		this.params.lineDashGap = getFN(atts["linedashgap"], 4);
		//Legend properties		
		this.params.showLegend = toBoolean(getFN(atts["showlegend"], 1));
		//Alignment position
		this.params.legendPosition = getFV(atts["legendposition"], "BOTTOM");
		//Legend position can be either RIGHT or BOTTOM -Check for it
		this.params.legendPosition = (this.params.legendPosition.toUpperCase()=="RIGHT")?"RIGHT":"BOTTOM";		
		this.params.legendBorderColor = formatColor(getFV(atts["legendbordercolor"], this.defColors.get2DLegendBorderColor(this.params.palette)));
		this.params.legendBorderThickness = getFN(atts["legendborderthickness"], 1);
		this.params.legendBorderAlpha = getFN(atts["legendborderalpha"], 100);
		this.params.legendBgColor = getFV(atts["legendbgcolor"], this.defColors.get2DLegendBgColor(this.params.palette));
		this.params.legendBgAlpha = getFN(atts["legendbgalpha"], 100);
		this.params.legendShadow = toBoolean(getFN(atts["legendshadow"], 1));
		this.params.legendAllowDrag = toBoolean(getFN(atts["legendallowdrag"], 0));
		this.params.legendScrollBgColor = formatColor(getFV(atts["legendscrollbgcolor"], "CCCCCC"));
		this.params.legendScrollBarColor = formatColor(getFV(atts["legendscrollbarcolor"], this.params.legendBorderColor));
		this.params.legendScrollBtnColor = formatColor(getFV(atts["legendscrollbtncolor"], this.params.legendBorderColor));
		//Horizontal grid division Lines - Number, color, thickness & alpha
		//Necessarily need a default value for numDivLines.
		this.params.numDivLines = getFN(atts["numdivlines"], 4);
		this.params.divLineColor = formatColor(getFV(atts["divlinecolor"], this.defColors.get2DDivLineColor(this.params.palette)));
		this.params.divLineThickness = getFN(atts["divlinethickness"], 1);
		this.params.divLineAlpha = getFN(atts["divlinealpha"], this.defColors.get2DDivLineAlpha(this.params.palette));
		this.params.divLineIsDashed = toBoolean(getFN(atts["divlineisdashed"], 0));
		this.params.divLineDashLen = getFN(atts["divlinedashlen"], 4);
		this.params.divLineDashGap = getFN(atts["divlinedashgap"], 2);
		//Vertical div lines		
		this.params.numVDivLines = getFN(atts["numvdivlines"], 0);
		this.params.vDivLineColor = formatColor(getFV(atts["vdivlinecolor"], this.params.divLineColor));
		this.params.vDivLineThickness = getFN(atts["vdivlinethickness"], this.params.divLineThickness);
		this.params.vDivLineAlpha = getFN(atts["vdivlinealpha"], this.params.divLineAlpha);
		this.params.vDivLineIsDashed = toBoolean(getFN(atts["vdivlineisdashed"], this.params.divLineIsDashed));
		this.params.vDivLineDashLen = getFN(atts["vdivlinedashlen"], this.params.divLineDashLen);
		this.params.vDivLineDashGap = getFN(atts["vdivlinedashgap"], this.params.divLineDashGap);
		//Zero Plane properties
		this.params.showZeroPlane = toBoolean(getFN(atts["showzeroplane"], 1));
		this.params.zeroPlaneColor = formatColor(getFV(atts["zeroplanecolor"], this.params.divLineColor));
		this.params.zeroPlaneThickness = getFN(atts["zeroplanethickness"], 1);
		this.params.zeroPlaneAlpha = getFN(atts["zeroplanealpha"], this.params.divLineAlpha);
		//Alternating grid colors
		this.params.showAlternateHGridColor = toBoolean(getFN(atts["showalternatehgridcolor"], 1));
		this.params.alternateHGridColor = formatColor(getFV(atts["alternatehgridcolor"], this.defColors.get2DAltHGridColor(this.params.palette)));
		this.params.alternateHGridAlpha = getFN(atts["alternatehgridalpha"], this.defColors.get2DAltHGridAlpha(this.params.palette));
		this.params.showAlternateVGridColor = toBoolean(getFN(atts["showalternatevgridcolor"], 0));
		this.params.alternateVGridColor = formatColor(getFV(atts["alternatevgridcolor"], this.defColors.get2DAltVGridColor(this.params.palette)));
		this.params.alternateVGridAlpha = getFN(atts["alternatevgridalpha"], this.defColors.get2DAltVGridAlpha(this.params.palette));
		//Shadow properties
		this.params.showShadow = toBoolean(getFN(atts["showshadow"], 1));
		//Anchor Properties
		this.params.drawAnchors = toBoolean(getFN(atts["drawanchors"], atts["showanchors"], 1));
		this.params.anchorSides = getFN(atts["anchorsides"], 10);
		this.params.anchorRadius = getFN(atts["anchorradius"], 3);
		this.params.anchorBorderColor = atts["anchorbordercolor"];
		this.params.anchorBorderThickness = getFN(atts["anchorborderthickness"], 1);
		this.params.anchorBgColor = formatColor(getFV(atts["anchorbgcolor"], this.defColors.get2DAnchorBgColor(this.params.palette)));
		this.params.anchorAlpha = getFN(atts["anchoralpha"], 100);
		this.params.anchorBgAlpha = getFN(atts["anchorbgalpha"], this.params.anchorAlpha);
		//Tool Tip - Show/Hide, Background Color, Border Color, Separator Character
		this.params.showToolTip = toBoolean(getFN(atts["showtooltip"], atts["showhovercap"], 1));
		this.params.seriesNameInToolTip = toBoolean(getFN(atts["seriesnameintooltip"], 1));
		this.params.toolTipBgColor = formatColor(getFV(atts["tooltipbgcolor"], atts["hovercapbgcolor"], atts["hovercapbg"], this.defColors.get2DToolTipBgColor(this.params.palette)));
		this.params.toolTipBorderColor = formatColor(getFV(atts["tooltipbordercolor"], atts["hovercapbordercolor"], atts["hovercapborder"], this.defColors.get2DToolTipBorderColor(this.params.palette)));
		this.params.toolTipSepChar = getFV(atts["tooltipsepchar"], atts["hovercapsepchar"], ", ");
		//Font Properties
		this.params.baseFont = getFV(atts["basefont"], "Verdana");
		this.params.baseFontSize = getFN(atts["basefontsize"], 10);
		this.params.baseFontColor = formatColor(getFV(atts["basefontcolor"], this.defColors.get2DBaseFontColor(this.params.palette)));
		this.params.outCnvBaseFont = getFV(atts["outcnvbasefont"], this.params.baseFont);
		this.params.outCnvBaseFontSize = getFN(atts["outcnvbasefontsize"], this.params.baseFontSize);
		this.params.outCnvBaseFontColor = formatColor(getFV(atts["outcnvbasefontcolor"], this.params.baseFontColor));
		// ------------------------- NUMBER FORMATTING ---------------------------- //
		//Option whether the format the number (using Commas)
		this.params.formatNumber = toBoolean(getFN(atts["formatnumber"], 1));
		//Option to format number scale
		this.params.formatNumberScale = toBoolean(getFN(atts["formatnumberscale"], 1));
		//Number Scales
		this.params.defaultNumberScale = getFV(atts["defaultnumberscale"], "");
		this.params.numberScaleUnit = getFV(atts["numberscaleunit"], "K,M");
		this.params.numberScaleValue = getFV(atts["numberscalevalue"], "1000,1000");
		//Number prefix and suffix
		//TODO: Escape them
		this.params.numberPrefix = getFV(atts["numberprefix"], "");
		this.params.numberSuffix = getFV(atts["numbersuffix"], "");
		//Decimal Separator Character
		this.params.decimalSeparator = getFV(atts["decimalseparator"], ".");
		//Thousand Separator Character
		this.params.thousandSeparator = getFV(atts["thousandseparator"], ",");
		//Input decimal separator and thousand separator. In some european countries,
		//commas are used as decimal separators and dots as thousand separators. In XML,
		//if the user specifies such values, it will give a error while converting to
		//number. So, we accept the input decimal and thousand separator from user, so that
		//we can covert it accordingly into the required format.
		this.params.inDecimalSeparator = getFV(atts["indecimalseparator"], "");
		this.params.inThousandSeparator = getFV(atts["inthousandseparator"], "");
		//Decimal Precision (number of decimal places to be rounded to)
		this.params.decimals = getFV(atts["decimals"], atts["decimalprecision"]);
		//Force Decimal Padding
		this.params.forceDecimals = toBoolean(getFN(atts["forcedecimals"], 0));
		//y-Axis values decimals
		this.params.yAxisValueDecimals = getFV(atts["yaxisvaluedecimals"], atts["yaxisvaluesdecimals"], atts["divlinedecimalprecision"], atts["limitsdecimalprecision"]);
	}
	/**
	 * getMaxDataValue method gets the maximum y-axis data value present
	 * in the data.
	 *	@returns	The maximum value present in the data provided.
	*/
	private function getMaxDataValue():Number {
		var maxValue:Number;
		var firstNumberFound:Boolean = false;
		var i:Number, j:Number;
		for (i=1; i<=this.numDS; i++) {
			for (j=1; j<=this.num; j++){
				//By default assume the first non-null number to be maximum
				if (firstNumberFound == false) {
					if (this.dataset[i].data[j].isDefined == true) {
						//Set the flag that "We've found first non-null number".
						firstNumberFound = true;
						//Also assume this value to be maximum.
						maxValue = this.dataset[i].data[j].value;
					}
				} else {
					//If the first number has been found and the current data is defined, compare
					if (this.dataset[i].data[j].isDefined) {
						//Store the greater number
						maxValue = (this.dataset[i].data[j].value>maxValue) ? this.dataset[i].data[j].value : maxValue;
					}
				}
			}
		}
		return maxValue;
	}
	/**
	 * getMinDataValue method gets the minimum y-axis data value present
	 * in the data
	 *	@reurns		The minimum value present in data
	*/
	private function getMinDataValue():Number {
		var minValue:Number;
		var firstNumberFound:Boolean = false;
		var i:Number, j:Number;
		for (i=1; i<=this.numDS; i++) {
			for (j=1; j<=this.num; j++){
				//By default assume the first non-null number to be minimum
				if (firstNumberFound == false) {
					if (this.dataset[i].data[j].isDefined == true) {
						//Set the flag that "We've found first non-null number".
						firstNumberFound = true;
						//Also assume this value to be minimum.
						minValue = this.dataset[i].data[j].value;
					}
				} else {
					//If the first number has been found and the current data is defined, compare
					if (this.dataset[i].data[j].isDefined) {
						//Store the lesser number					
						minValue = (this.dataset[i].data[j].value<minValue) ? this.dataset[i].data[j].value : minValue;
					}
				}
			}
		}
		return minValue;
	}
	/**
	* calculateAxisLimits method sets the axis limits for the chart.
	* It gets the minimum and maximum value specified in data and
	* based on that it calls super.getAxisLimits();
	*/
	private function calculateAxisLimits():Void {
		this.getAxisLimits(this.getMaxDataValue(), this.getMinDataValue(), false, !this.params.setAdaptiveYMin);
	}
	/**
	* setStyleDefaults method sets the default values for styles or
	* extracts information from the attributes and stores them into
	* style objects.
	*/
	private function setStyleDefaults():Void {
		//Default font object for Caption
		//-----------------------------------------------------------------//
		var captionFont = new StyleObject();
		captionFont.name = "_SdCaptionFont";
		captionFont.align = "center";
		captionFont.valign = "top";
		captionFont.bold = "1";
		captionFont.font = this.params.outCnvBaseFont;
		captionFont.size = this.params.outCnvBaseFontSize;
		captionFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle(this.objects.CAPTION, captionFont, this.styleM.TYPE.FONT, null);
		delete captionFont;
		//-----------------------------------------------------------------//
		//Default font object for SubCaption
		//-----------------------------------------------------------------//
		var subCaptionFont = new StyleObject();
		subCaptionFont.name = "_SdSubCaptionFont";
		subCaptionFont.align = "center";
		subCaptionFont.valign = "top";
		subCaptionFont.bold = "1";
		subCaptionFont.font = this.params.outCnvBaseFont;
		subCaptionFont.size = this.params.outCnvBaseFontSize;
		subCaptionFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle(this.objects.SUBCAPTION, subCaptionFont, this.styleM.TYPE.FONT, null);
		delete subCaptionFont;
		//-----------------------------------------------------------------//
		//Default font object for YAxisName
		//-----------------------------------------------------------------//
		var yAxisNameFont = new StyleObject();
		yAxisNameFont.name = "_SdYAxisNameFont";
		yAxisNameFont.align = "center";
		yAxisNameFont.valign = "middle";
		yAxisNameFont.bold = "1";
		yAxisNameFont.font = this.params.outCnvBaseFont;
		yAxisNameFont.size = this.params.outCnvBaseFontSize;
		yAxisNameFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle(this.objects.YAXISNAME, yAxisNameFont, this.styleM.TYPE.FONT, null);
		delete yAxisNameFont;
		//-----------------------------------------------------------------//
		//Default font object for XAxisName
		//-----------------------------------------------------------------//
		var xAxisNameFont = new StyleObject();
		xAxisNameFont.name = "_SdXAxisNameFont";
		xAxisNameFont.align = "center";
		xAxisNameFont.valign = "middle";
		xAxisNameFont.bold = "1";
		xAxisNameFont.font = this.params.outCnvBaseFont;
		xAxisNameFont.size = this.params.outCnvBaseFontSize;
		xAxisNameFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle(this.objects.XAXISNAME, xAxisNameFont, this.styleM.TYPE.FONT, null);
		delete xAxisNameFont;
		//-----------------------------------------------------------------//
		//Default font object for trend lines
		//-----------------------------------------------------------------//
		var trendFont = new StyleObject();
		trendFont.name = "_SdTrendFontFont";
		trendFont.font = this.params.outCnvBaseFont;
		trendFont.size = this.params.outCnvBaseFontSize;
		trendFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle(this.objects.TRENDVALUES, trendFont, this.styleM.TYPE.FONT, null);
		delete trendFont;
		//-----------------------------------------------------------------//
		//Default font object for yAxisValues
		//-----------------------------------------------------------------//
		var yAxisValuesFont = new StyleObject();
		yAxisValuesFont.name = "_SdYAxisValuesFont";
		yAxisValuesFont.align = "right";
		yAxisValuesFont.valign = "middle";
		yAxisValuesFont.font = this.params.outCnvBaseFont;
		yAxisValuesFont.size = this.params.outCnvBaseFontSize;
		yAxisValuesFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle(this.objects.YAXISVALUES, yAxisValuesFont, this.styleM.TYPE.FONT, null);
		delete yAxisValuesFont;
		//-----------------------------------------------------------------//
		//Default font object for DataLabels
		//-----------------------------------------------------------------//
		var dataLabelsFont = new StyleObject();
		dataLabelsFont.name = "_SdDataLabelsFont";
		dataLabelsFont.align = "center";
		dataLabelsFont.valign = "bottom";
		dataLabelsFont.font = this.params.catFont;
		dataLabelsFont.size = this.params.catFontSize;
		dataLabelsFont.color = this.params.catFontColor;
		//Over-ride
		this.styleM.overrideStyle(this.objects.DATALABELS, dataLabelsFont, this.styleM.TYPE.FONT, null);
		delete dataLabelsFont;
		//-----------------------------------------------------------------//
		//Default font object for Legend
		//-----------------------------------------------------------------//
		var legendFont = new StyleObject();
		legendFont.name = "_SdLegendFont";
		legendFont.font = this.params.outCnvBaseFont;
		legendFont.size = this.params.outCnvBaseFontSize;
		legendFont.color = this.params.outCnvBaseFontColor;
		legendFont.ishtml = 1;
		legendFont.leftmargin = 3;
		//Over-ride
		this.styleM.overrideStyle(this.objects.LEGEND, legendFont, this.styleM.TYPE.FONT, null);
		delete legendFont;
		//-----------------------------------------------------------------//
		//Default font object for DataValues
		//-----------------------------------------------------------------//
		var dataValuesFont = new StyleObject();
		dataValuesFont.name = "_SdDataValuesFont";
		dataValuesFont.align = "center";
		dataValuesFont.valign = "middle";
		dataValuesFont.font = this.params.baseFont;
		dataValuesFont.size = this.params.baseFontSize;
		dataValuesFont.color = this.params.baseFontColor;
		//Over-ride
		this.styleM.overrideStyle(this.objects.DATAVALUES, dataValuesFont, this.styleM.TYPE.FONT, null);
		delete dataValuesFont;
		//-----------------------------------------------------------------//
		//Default font object for ToolTip
		//-----------------------------------------------------------------//
		var toolTipFont = new StyleObject();
		toolTipFont.name = "_SdToolTipFont";
		toolTipFont.font = this.params.baseFont;
		toolTipFont.size = this.params.baseFontSize;
		toolTipFont.color = this.params.baseFontColor;
		toolTipFont.bgcolor = this.params.toolTipBgColor;
		toolTipFont.bordercolor = this.params.toolTipBorderColor;
		//Over-ride
		this.styleM.overrideStyle(this.objects.TOOLTIP, toolTipFont, this.styleM.TYPE.FONT, null);
		delete toolTipFont;
		//-----------------------------------------------------------------//
		//Default Effect (Shadow) object for DataPlot
		//-----------------------------------------------------------------//
		if (this.params.showShadow) {
			var dataPlotShadow = new StyleObject();
			dataPlotShadow.name = "_SdDataPlotShadow";
			dataPlotShadow.angle = 45;
			//Over-ride         
			this.styleM.overrideStyle(this.objects.DATAPLOT, dataPlotShadow, this.styleM.TYPE.SHADOW, null);
			delete dataPlotShadow;
		}
		//-----------------------------------------------------------------//
		//Default Effect (Shadow) object for Legend
		//-----------------------------------------------------------------//
		if (this.params.legendShadow){
			var legendShadow = new StyleObject();
			legendShadow.name = "_SdLegendShadow";
			legendShadow.distance = 2;
			legendShadow.alpha =90;
			legendShadow.angle =45;
			//Over-ride     
			this.styleM.overrideStyle(this.objects.LEGEND, legendShadow, this.styleM.TYPE.SHADOW, null);
			delete legendShadow;
		}
		//-----------------------------------------------------------------//
		//Default Animation object for DataPlot (if required)
		//-----------------------------------------------------------------//
		if (this.params.defaultAnimation) {
			//We need three animation objects.
			//1. XScale for data plot						
			var dataPlotAnim = new StyleObject();
			dataPlotAnim.name = "_SdDataPlotAnimXScale";
			dataPlotAnim.param = "_xscale";
			dataPlotAnim.easing = "regular";
			dataPlotAnim.wait = 0;
			dataPlotAnim.start = 0;
			dataPlotAnim.duration = 0.7;
			//Over-ride
			this.styleM.overrideStyle(this.objects.DATAPLOT, dataPlotAnim, this.styleM.TYPE.ANIMATION, "_xscale");
			delete dataPlotAnim;
			//2. YScale for data plot
			var dataPlotAnimY = new StyleObject();
			dataPlotAnimY.name = "_SdDataPlotAnimYScale";
			dataPlotAnimY.param = "_yscale";
			dataPlotAnimY.easing = "regular";
			dataPlotAnimY.wait = 0.7;
			dataPlotAnimY.start = 0.1;
			dataPlotAnimY.duration = 0.7;
			//Over-ride
			this.styleM.overrideStyle(this.objects.DATAPLOT, dataPlotAnimY, this.styleM.TYPE.ANIMATION, "_yscale");
			delete dataPlotAnimY;
			//3. Alpha effect for anchors				
			var anchorsAnim = new StyleObject();
			anchorsAnim.name = "_SdDataAnchorAnim";
			anchorsAnim.param = "_alpha";
			anchorsAnim.easing = "regular";
			anchorsAnim.wait = 0;
			anchorsAnim.start = 0;
			anchorsAnim.duration = 0.5;
			//Over-ride
			this.styleM.overrideStyle(this.objects.ANCHORS, anchorsAnim, this.styleM.TYPE.ANIMATION, "_alpha");
			this.styleM.overrideStyle(this.objects.SCROLLPANE, anchorsAnim, this.styleM.TYPE.ANIMATION, "_alpha");
			delete anchorsAnim;
		}
		//-----------------------------------------------------------------//    
	}
	/**
	 * calcVLinesPos method calculates the x position for the various
	 * vLines defined. Also, it validates them.
	*/
	private function calcVLinesPos() {
		var i:Number;
		//Iterate through all the vLines
		for (i=1; i<=numVLines; i++) {
			//If the vLine is after 1st data and before last data
			if (this.vLines[i].index>0 && this.vLines[i].index<this.num) {
				//Set it's x position
				this.vLines[i].x = this.categories[this.vLines[i].index].x+(this.categories[this.vLines[i].index+1].x-this.categories[this.vLines[i].index].x)/2;
			} else {
				//Invalidate it
				this.vLines[i].isValid = false;
			}
		}
	}
	/**
	* calculatePoints method calculates the various points on the chart.
	*/
	private function calculatePoints() {
		//Loop variable
		var i:Number;
		var j:Number;
		//Feed empty data - By default there should be equal number of <categories>
		//and <set> element within each dataset. If in case, <set> elements fall short,
		//we need to append empty data at the end.
		for (i=1; i<=this.numDS; i++){
			for (j=1; j<=this.num; j++){
				if (this.dataset[i].data[j] == undefined){
					this.dataset[i].data[j] = this.returnDataAsObject(NaN);
				}
			}
		}
		//If the user has not specified number of plots to be made visible by default,
		//we need to assume a value.
		if(this.params.numVisiblePlot ==undefined || this.params.numVisiblePlot=="" || isNaN(this.params.numVisiblePlot)){
			//If the number of data items is more than our Constant value of 10,
			//we'll show only n/2 items by default. Rest would be available upon
			//scrolling.
			if(this.num > MIN_SCROLLPOINTS ) {				
				this.params.numVisiblePlot = Math.abs(getFN(this.params.numVisiblePlot, Math.ceil(this.num/2)));
			} else {
				//Else, we show all the data items by default.
				this.params.numVisiblePlot = this.num;
			}
		} 
		// numVisiblePlot cannot be more than the max point or less than 2
		if(this.params.numVisiblePlot < 2 ||  this.params.numVisiblePlot > this.num)  {
			this.params.numVisiblePlot = this.num;
		}
		//Format all the numbers on the chart and store their display values
		//We format and store here itself, so that later, whenever needed,
		//we just access displayValue instead of formatting once again.
		//Also set tool tip text values
		var toolText:String
		for (i=1; i<=this.numDS; i++) {
			for (j=1; j<=this.num; j++){
				//Format and store
				this.dataset[i].data[j].displayValue = formatNumber(this.dataset[i].data[j].value, this.params.formatNumber, this.params.decimals, this.params.forceDecimals, this.params.formatNumberScale, this.params.defaultNumberScale, this.config.nsv, this.config.nsu, this.params.numberPrefix, this.params.numberSuffix);
				//Tool tip text.
				//Preferential Order - Set Tool Text (No concatenation) > SeriesName + Cat Name + Value
				if (this.dataset[i].data[j].toolText==undefined || this.dataset[i].data[j].toolText==""){
					//If the tool tip text is not already defined
					//If labels have been defined
					toolText = (this.params.seriesNameInToolTip && this.dataset[i].seriesName!="")?(this.dataset[i].seriesName + this.params.toolTipSepChar):"";
					toolText = toolText + ((this.categories[j].toolText!="")?(this.categories[j].toolText + this.params.toolTipSepChar):"");
					toolText = toolText + this.dataset[i].data[j].displayValue;
					this.dataset[i].data[j].toolText = toolText;
				}				
			}
		}
		//Based on label step, set showLabel of each data point as required.
		//Visible label count
		var visibleCount:Number = 0;
		var finalVisibleCount:Number = 0;
		for (i=1; i<=this.num; i++) {
			//Now, the label can be preset to be hidden (set via XML)
			if (this.categories[i].showLabel) {
				visibleCount++;
				//If label step is defined, we need to set showLabel of those
				//labels which fall on step as false.
				if ((i-1)%this.params.labelStep == 0) {
					this.categories[i].showLabel = true;
				} else {
					this.categories[i].showLabel = false;
				}
			}
			//Update counter     
			finalVisibleCount = (this.categories[i].showLabel) ? (finalVisibleCount+1) : (finalVisibleCount);
		}
		//We now need to calculate the available Width on the canvas.
		//Available width = total Chart width minus the list below
		// - Left and Right Margin
		// - yAxisName (if to be shown)
		// - yAxisValues
		// - Trend line display values (both left side and right side).
		// - Legend (If to be shown at right)
		var canvasWidth:Number = this.width-(this.params.chartLeftMargin+this.params.chartRightMargin);
		//Set canvas startX
		var canvasStartX:Number = this.params.chartLeftMargin;
		//Now, if y-axis name is to be shown, simulate it and get the width
		if (this.params.yAxisName != "") {
			//Get style object
			var yAxisNameStyle:Object = this.styleM.getTextStyle(this.objects.YAXISNAME);
			if (this.params.rotateYAxisName) {
				//Set embedded font - as we need to rotate
				yAxisNameStyle.font = _embeddedFont;
				//Un-bold and un-italicize
				yAxisNameStyle.bold = false;
				yAxisNameStyle.italic = false;
				//Create text field to get width
				var yAxisNameObj:Object = createText(true, this.params.yAxisName, this.tfTestMC, 1, testTFX, testTFY, 90, yAxisNameStyle, false, 0, 0);
				//Accomodate width and padding
				canvasStartX = canvasStartX+yAxisNameObj.width+this.params.yAxisNamePadding;
				canvasWidth = canvasWidth-yAxisNameObj.width-this.params.yAxisNamePadding;
				//Create element for yAxisName - to store width/height
				this.elements.yAxisName = returnDataAsElement(0, 0, yAxisNameObj.width, yAxisNameObj.height);
			} else {
				//If the y-axis name is not to be rotated
				//Calculate the width of the text if in full horizontal mode
				//Create text field to get width
				var yAxisNameObj:Object = createText(true, this.params.yAxisName, this.tfTestMC, 1, testTFX, testTFY, 0, yAxisNameStyle, false, 0, 0);
				//Get a value for this.params.yAxisNameWidth
				this.params.yAxisNameWidth = Number(getFV(this.params.yAxisNameWidth, yAxisNameObj.width));
				//Get the lesser of the width (to avoid un-necessary space)				
				this.params.yAxisNameWidth = Math.min(this.params.yAxisNameWidth, yAxisNameObj.width);
				//Accomodate width and padding
				canvasStartX = canvasStartX+this.params.yAxisNameWidth+this.params.yAxisNamePadding;
				canvasWidth = canvasWidth-this.params.yAxisNameWidth-this.params.yAxisNamePadding;
				//Create element for yAxisName - to store width/height
				this.elements.yAxisName = returnDataAsElement(0, 0, this.params.yAxisNameWidth, yAxisNameObj.height);
			}
			delete yAxisNameStyle;
			delete yAxisNameObj;
		}
		//Accomodate width for y-axis values. Now, y-axis values conists of two parts         
		//(for backward compatibility) - limits (upper and lower) and div line values.
		//So, we'll have to individually run through both of them.
		var yAxisValMaxWidth:Number = 0;
		var divLineObj:Object;
		var divStyle:Object = this.styleM.getTextStyle(this.objects.YAXISVALUES);
		//Iterate through all the div line values
		for (i=1; i<this.divLines.length; i++) {
			//If div line value is to be shown
			if (this.divLines[i].showValue) {
				//If it's the first or last div Line (limits), and it's to be shown
				if ((i == 1) || (i == this.divLines.length-1)) {
					if (this.params.showLimits) {
						//Get the width of the text
						divLineObj = createText(true, this.divLines[i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, divStyle, false, 0, 0);
						//Accomodate
						yAxisValMaxWidth = (divLineObj.width>yAxisValMaxWidth) ? (divLineObj.width) : (yAxisValMaxWidth);
					}
				} else {
					//It's a div interval - div line
					//So, check if we've to show div line values
					if (this.params.showDivLineValues) {
						//Get the width of the text
						divLineObj = createText(true, this.divLines[i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, divStyle, false, 0, 0);
						//Accomodate
						yAxisValMaxWidth = (divLineObj.width>yAxisValMaxWidth) ? (divLineObj.width) : (yAxisValMaxWidth);
					}
				}
			}
		}
		delete divLineObj;
		//Also iterate through all trend lines whose values are to be shown on
		//left side of the canvas.
		//Get style object
		var trendStyle:Object = this.styleM.getTextStyle(this.objects.TRENDVALUES);
		var trendObj:Object;
		for (i=1; i<=this.numTrendLines; i++) {
			if (this.trendLines[i].isValid == true && this.trendLines[i].valueOnRight == false) {
				//If it's a valid trend line and value is to be shown on left
				//Get the width of the text
				trendObj = createText(true, this.trendLines[i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, trendStyle, false, 0, 0);
				//Accomodate
				yAxisValMaxWidth = (trendObj.width>yAxisValMaxWidth) ? (trendObj.width) : (yAxisValMaxWidth);
			}
		}
		//Accomodate for y-axis/left-trend line values text width
		if (yAxisValMaxWidth>0) {
			canvasStartX = canvasStartX+yAxisValMaxWidth+this.params.yAxisValuesPadding;
			canvasWidth = canvasWidth-yAxisValMaxWidth-this.params.yAxisValuesPadding;
		}
		var trendRightWidth:Number = 0;
		//Now, also check for trend line values that fall on right
		for (i=1; i<=this.numTrendLines; i++) {
			if (this.trendLines[i].isValid == true && this.trendLines[i].valueOnRight == true) {
				//If it's a valid trend line and value is to be shown on right
				//Get the width of the text
				trendObj = createText(true, this.trendLines[i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, trendStyle, false, 0, 0);
				//Accomodate
				trendRightWidth = (trendObj.width>trendRightWidth) ? (trendObj.width) : (trendRightWidth);
			}
		}
		delete trendObj;
		//Accomodate trend right text width
		if (trendRightWidth>0) {
			canvasWidth = canvasWidth-trendRightWidth-this.params.yAxisValuesPadding;
		}
		//Round them off finally to avoid distorted pixels    
		canvasStartX = int(canvasStartX);
		canvasWidth = int(canvasWidth);
		//We finally have canvas Width and canvas Start X
		//-----------------------------------------------------------------------------------//
		//Now, we need to calculate the available Height on the canvas.
		//Available height = total Chart height minus the list below
		// - Chart Top and Bottom Margins
		// - Space for Caption, Sub Caption and caption padding
		// - Height of data labels
		// - xAxisName
		// - Legend (If to be shown at bottom position)
		//Initialize canvasHeight to total height minus margins
		var canvasHeight:Number = this.height-(this.params.chartTopMargin+this.params.chartBottomMargin);
		//Set canvasStartY
		var canvasStartY:Number = this.params.chartTopMargin;
		//Now, if we've to show caption
		if (this.params.caption != "") {
			//Create text field to get height
			var captionObj:Object = createText(true, this.params.caption, this.tfTestMC, 1, testTFX, testTFY, 0, this.styleM.getTextStyle(this.objects.CAPTION), false, 0, 0);
			//Store the height
			canvasStartY = canvasStartY+captionObj.height;
			canvasHeight = canvasHeight-captionObj.height;
			//Create element for caption - to store width & height
			this.elements.caption = returnDataAsElement(0, 0, captionObj.width, captionObj.height);
			delete captionObj;
		}
		//Now, if we've to show sub-caption         
		if (this.params.subCaption != "") {
			//Create text field to get height
			var subCaptionObj:Object = createText(true, this.params.subCaption, this.tfTestMC, 1, testTFX, testTFY, 0, this.styleM.getTextStyle(this.objects.SUBCAPTION), false, 0, 0);
			//Store the height
			canvasStartY = canvasStartY+subCaptionObj.height;
			canvasHeight = canvasHeight-subCaptionObj.height;
			//Create element for sub caption - to store height
			this.elements.subCaption = returnDataAsElement(0, 0, subCaptionObj.width, subCaptionObj.height);
			delete subCaptionObj;
		}
		//Now, if either caption or sub-caption was shown, we also need to adjust caption padding         
		if (this.params.caption != "" || this.params.subCaption != "") {
			//Account for padding
			canvasStartY = canvasStartY+this.params.captionPadding;
			canvasHeight = canvasHeight-this.params.captionPadding;
		}
		//Now, if data labels are to be shown, we need to account for their heights     
		//Data labels can be rendered in 3 ways:
		//1. Normal - no staggering - no wrapping - no rotation
		//2. Wrapped - no staggering - no rotation
		//3. Staggered - no wrapping - no rotation
		//4. Rotated - no staggering - no wrapping
		//Placeholder to store max height
		this.config.maxLabelHeight = 0;
		this.config.labelAreaHeight = 0;
		var labelObj:Object;
		var labelStyleObj:Object = this.styleM.getTextStyle(this.objects.DATALABELS);
		if (this.params.labelDisplay == "ROTATE") {
			//Case 4: If the labels are rotated, we iterate through all the string labels
			//provided to us and get the height and store max.
			for (i=1; i<=this.num; i++) {
				//If the label is to be shown
				if (this.categories[i].showLabel) {
					//Set style bold/italic to false and font to embedded font
					labelStyleObj.font = _embeddedFont;
					labelStyleObj.bold = false;
					labelStyleObj.italic = false;
					//Create text box and get height
					labelObj = createText(true, this.categories[i].label, this.tfTestMC, 1, testTFX, testTFY, this.config.labelAngle, labelStyleObj, false, 0, 0);
					//Store the larger
					this.config.maxLabelHeight = (labelObj.height>this.config.maxLabelHeight) ? (labelObj.height) : (this.config.maxLabelHeight);
				}
			}
			//Store max label height as label area height.
			this.config.labelAreaHeight = this.config.maxLabelHeight;
		} else if (this.params.labelDisplay == "WRAP") {
			//Case 2 (WRAP): Create all the labels on the chart. Set width as
			//totalAvailableWidth/finalVisibleCount.
			//Set max height as 50% of available canvas height at this point of time. Find all
			//and select the max one.
			var maxLabelWidth : Number = (canvasWidth*(this.num/this.params.numVisiblePlot)/ finalVisibleCount);
			var maxLabelHeight:Number = (canvasHeight/2);
			//Store it in config for later usage
			this.config.wrapLabelWidth = maxLabelWidth;
			this.config.wrapLabelHeight = maxLabelHeight;
			for (i=1; i<=this.num; i++) {
				//If the label is to be shown
				if (this.categories[i].showLabel) {
					//Create text box and get height
					labelObj = createText(true, this.categories[i].label, this.tfTestMC, 1, testTFX, testTFY, 0, labelStyleObj, true, maxLabelWidth, maxLabelHeight);
					//Store the larger
					this.config.maxLabelHeight = (labelObj.height>this.config.maxLabelHeight) ? (labelObj.height) : (this.config.maxLabelHeight);
				}
			}
			//Store max label height as label area height.
			this.config.labelAreaHeight = this.config.maxLabelHeight;
		} else {
			//Case 1,3: Normal or Staggered Label
			//We iterate through all the labels, and if any of them has &lt or < (HTML marker)
			//embedded in them, we add them to the array, as for them, we'll need to individually
			//create and see the text height. Also, the first element in the array - we set as
			//ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_=....
			//Create array to store labels.
			var strLabels:Array = new Array();
			strLabels.push("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_=/*-+~`");
			//Now, iterate through all the labels and for those visible labels, whcih have < sign,
			//add it to array.
			for (i=1; i<=this.num; i++) {
				//If the label is to be shown
				if (this.categories[i].showLabel) {
					if ((this.categories[i].label.indexOf("&lt;")>-1) || (this.categories[i].label.indexOf("<")>-1)) {
						strLabels.push(this.categories[i].label);
					}
				}
			}
			//Now, we've the array for which we've to check height (for each element).
			for (i=0; i<strLabels.length; i++) {
				//Create text box and get height
				labelObj = createText(true, this.categories[i].label, this.tfTestMC, 1, testTFX, testTFY, 0, labelStyleObj, false, 0, 0);
				//Store the larger
				this.config.maxLabelHeight = (labelObj.height>this.config.maxLabelHeight) ? (labelObj.height) : (this.config.maxLabelHeight);
			}
			//We now have the max label height. If it's staggered, then store accordingly, else
			//simple mode
			if (this.params.labelDisplay == "STAGGER") {
				//Multiply max label height by stagger lines.
				this.config.labelAreaHeight = this.params.staggerLines*this.config.maxLabelHeight;
			} else {
				this.config.labelAreaHeight = this.config.maxLabelHeight;
			}
		}
		if (this.config.labelAreaHeight>0) {
			//Deduct the calculated label height from canvas height
			canvasHeight = canvasHeight-this.config.labelAreaHeight-this.params.labelPadding;
		}
		//Delete objects       
		delete labelObj;
		delete labelStyleObj;
		//Deduct Height required for the scrollPane Component ( if Required )
		if(this.params.numVisiblePlot != this.num)  {
			this.config.scrollRequired = true;
			canvasHeight = canvasHeight-this.scrollHeight;
		}
		//Accomodate space for xAxisName (if to be shown);
		if (this.params.xAxisName != "") {
			//Create text field to get height
			var xAxisNameObj:Object = createText(true, this.params.xAxisName, this.tfTestMC, 1, testTFX, testTFY, 0, this.styleM.getTextStyle(this.objects.XAXISNAME), false, 0, 0);
			//Store the height
			canvasHeight = canvasHeight-xAxisNameObj.height-this.params.xAxisNamePadding;
			//Object to store width and height of xAxisName
			this.elements.xAxisName = returnDataAsElement(0, 0, xAxisNameObj.width, xAxisNameObj.height);
			delete xAxisNameObj;
		}
		//We have canvas start Y and canvas height     
		//We now check whether the legend is to be drawn 
		if (this.params.showLegend){
			//Object to store dimensions
			var lgndDim:Object = lgnd.getDimensions();
			//Create container movie clip for legend
			this.lgndMC = this.cMC.createEmptyMovieClip("Legend",this.dm.getDepth("LEGEND"));
			//Create instance of legend			
			if (this.params.legendPosition=="BOTTOM"){
				//Maximum Height - 50% of stage
				lgnd = new Legend(lgndMC, this.styleM.getTextStyle(this.objects.LEGEND), this.params.legendPosition, canvasStartX + canvasWidth/2, this.height/2, canvasWidth, (this.height-(this.params.chartTopMargin+this.params.chartBottomMargin))*0.5, this.params.legendAllowDrag, this.width, this.height, this.params.legendBgColor, this.params.legendBgAlpha, this.params.legendBorderColor, this.params.legendBorderThickness, this.params.legendBorderAlpha, this.params.legendScrollBgColor, this.params.legendScrollBarColor, this.params.legendScrollBtnColor);
			}
			else {
				//Maximum Width - 40% of stage
				lgnd = new Legend(lgndMC, this.styleM.getTextStyle(this.objects.LEGEND), this.params.legendPosition, this.width/2, canvasStartY + canvasHeight/2, (this.width-(this.params.chartLeftMargin+this.params.chartRightMargin))*0.4, canvasHeight, this.params.legendAllowDrag, this.width, this.height, this.params.legendBgColor, this.params.legendBgAlpha, this.params.legendBorderColor, this.params.legendBorderThickness, this.params.legendBorderAlpha, this.params.legendScrollBgColor, this.params.legendScrollBarColor, this.params.legendScrollBtnColor);			
			}
			//Feed data set series Name for legend
			for (i=1; i<=this.numDS; i++){
				if (this.dataset[i].includeInLegend && this.dataset[i].seriesName!=""){
					lgnd.addItem(this.dataset[i].seriesName, this.dataset[i].color);
				}
			}			
			if (this.params.legendPosition=="BOTTOM"){
				lgndDim = lgnd.getDimensions();
				//Now deduct the height from the calculated canvas height
				canvasHeight = canvasHeight-lgndDim.height-this.params.legendPadding;
				//Re-set the legend position
				this.lgnd.resetXY(canvasStartX + canvasWidth/2, this.height - this.params.chartBottomMargin - lgndDim.height/2);
			}
			else{
				//Get dimensions
				lgndDim = lgnd.getDimensions();
				//Now deduct the width from the calculated canvas width
				canvasWidth = canvasWidth-lgndDim.width-this.params.legendPadding;
				//Right position
				this.lgnd.resetXY(this.width - this.params.chartRightMargin - lgndDim.width/2, canvasStartY + canvasHeight/2);
			}
		}
		//Create an element to represent the canvas now.
		this.elements.canvas = returnDataAsElement(canvasStartX, canvasStartY, canvasWidth, canvasHeight);
		//We now need to calculate the position of lines on the chart.
		//Now, calculate the width between two points on chart
		if(this.params.numVisiblePlot >1) {
			var interPointWidth:Number = (this.elements.canvas.w-(2*this.params.canvasPadding))/(this.params.numVisiblePlot-1);
		} else {
			var interPointWidth:Number = (this.elements.canvas.w/2)/(this.params.numVisiblePlot);
		}
		//If no scroller reduce the space required for the ScrollPane
		if(!this.config.scrollRequired)  {
			this.scrollHeight = 0;
		}
		for (i=1; i<=this.numDS; i++){
		//Now, store the positions of the points
			for (j=1; j<=this.num; j++) {
				//Now, if there is only 1 point on the chart, we center it. Else, we get even X.
				this.dataset[i].data[j].x = (this.params.num == 1) ? (this.elements.canvas.w/2) : (this.params.canvasPadding+(interPointWidth*(j-1)));
				if (i==1){
					this.categories[j].x = this.dataset[i].data[j].x;
				}
				//Set the y position
				this.dataset[i].data[j].y = this.getAxisPosition(this.dataset[i].data[j].value, this.config.yMax, this.config.yMin, 0, this.elements.canvas.h, true, 0);
				//Store value textbox y position
				this.dataset[i].data[j].valTBY = this.dataset[i].data[j].y;
			}
		}
		//Store the name of the CanvasMC as we need to draw the vertical Lines
		// which is drawn in the parent class
		this.config.canvasMCName = "CanvasMC";
		//Create a MC for the all the canvas related API's
		this.canvasMC = this.cMC.createEmptyMovieClip("CanvasMC", this.dm.getDepth("SCROLLCANVAS"));
		//We create 2 different MovieClips within the canvasMC to solve the problem of having an extra 
		// space on the right of the canvas as we do not get the exact width of the canvas. Flash is returning
		// the width of the canvas including the values and label - but we do not want that to be considered while
		//rendering the chart.
		//So we have seperated canvasMC in 2 parts - one has all the drawing API's of the canvas and other has all
		// the text related.
		//Create MC for drawing within the canvas MC
		this.drawCanvasMC = this.canvasMC.createEmptyMovieClip("DrawPlot_Canvas", this.canvasMC.getNextHighestDepth());
		//Draw a hidden line - we create a hidden line spanning the whole width of the chart - since flash internally
		//returns the width of the MC as the width of the API drawn within and we need width with respect to starting
		//position of the API in the parent MC. So, we have created a maximum possible line in the parent MC and hence
		//flash returns the actual width of the MC which we require.
		this.drawCanvasMC.createEmptyMovieClip("HiddenLine", this.drawCanvasMC.getNextHighestDepth());
		this.drawCanvasMC.lineStyle(1, 0x000000, 0);
		this.drawCanvasMC.moveTo(0, 0);
		this.drawCanvasMC.lineTo((this.categories[this.num].x+this.params.canvasPadding), 0);
		//Text Canvas MC stores all the text related component of the canvas
		//In text canvas MC we get the depth as the next highest possible depth and we do not keep
		//DATALABELS and DATAPLOT into consideration for allotment of depth in the depth Manager -
		// this is just to make the code optimize.
		this.textCanvasMC = this.canvasMC.createEmptyMovieClip("text_Canvas", this.canvasMC.getNextHighestDepth());
		//Set the position with repect to cMC
		this.canvasMC._x = this.elements.canvas.x;
		this.canvasMC._y = this.elements.canvas.y;
		//Set the position 0, 0 within the parent MC
		this.drawCanvasMC._x = 0;
		this.textCanvasMC._x = 0;
	}
	/**
	 * allotCanvasDepths method allots the depths for various canvas objects
	 * to be rendered. We do this before hand, so that we can later just
	 * go on rendering chart objects, without swapping.
	*/
	private function allotCanvasDepths():Void {
		//Vertical div lines
		this.canvasDm.reserveDepths("VLINES", this.numVLines);
		//Data Plot
		this.canvasDm.reserveDepths("DATAPLOT", this.num*this.numDS);
		//Anchors
		this.canvasDm.reserveDepths("ANCHORS", this.num*this.numDS);
	}
	/**
	 * allotDepths method allots the depths for various chart objects
	 * to be rendered. We do this before hand, so that we can later just
	 * go on rendering chart objects, without swapping.
	*/
	private function allotDepths():Void {
		//Background
		this.dm.reserveDepths("BACKGROUND", 1);
		//Click URL Handler
		this.dm.reserveDepths("CLICKURLHANDLER", 1);
		//Background SWF
		this.dm.reserveDepths("BGSWF", 1);
		//Canvas
		this.dm.reserveDepths("CANVAS", 1);
		//If vertical grid is to be shown
		if (this.params.showAlternateVGridColor) {
			this.dm.reserveDepths("VGRID", Math.ceil((this.params.numVDivLines+1)/2));
		}
		//If horizontal grid is to be shown    
		if (this.params.showAlternateHGridColor) {
			this.dm.reserveDepths("HGRID", Math.ceil((this.divLines.length+1)/2));
		}
		//Vertical Div Lines    
		this.dm.reserveDepths("VDIVLINES", this.params.numVDivLines);
		//Div Lines and their labels
		this.dm.reserveDepths("DIVLINES", (this.divLines.length*2));
		//Zero Plane
		this.dm.reserveDepths("ZEROPLANE", 2);
		//Caption
		this.dm.reserveDepths("CAPTION", 1);
		//Sub-caption
		this.dm.reserveDepths("SUBCAPTION", 1);
		//X-Axis Name
		this.dm.reserveDepths("XAXISNAME", 1);
		//Y-Axis Name
		this.dm.reserveDepths("YAXISNAME", 1);
		//Trend lines below plot (lines and their labels)
		this.dm.reserveDepths("TRENDLINESBELOW", this.numTrendLinesBelow);
		this.dm.reserveDepths("TRENDVALUESBELOW", this.numTrendLinesBelow);		
		//ScrollChart MC
		this.dm.reserveDepths("SCROLLMC", 1);
		//Line Chart
		this.dm.reserveDepths("MASK", 1);
		//Canvas
		this.dm.reserveDepths("SCROLLCANVAS", 1);
		//Trend lines below plot (lines and their labels)
		this.dm.reserveDepths("TRENDLINESABOVE", (this.numTrendLines-this.numTrendLinesBelow));
		this.dm.reserveDepths("TRENDVALUESABOVE", (this.numTrendLines-this.numTrendLinesBelow));
		//Canvas Border
		this.dm.reserveDepths("CANVASBORDER", 1);
		//Legend
		this.dm.reserveDepths("LEGEND", 1);
	}
	//--------------- VISUAL RENDERING METHODS -------------------------//
	/**
	* drawHeaders method renders the following on the chart:
	* CAPTION, SUBCAPTION, XAXISNAME, YAXISNAME
	*/
	private function drawHeaders() {
		//Render caption
		if (this.params.caption != "") {
			var captionStyleObj:Object = this.styleM.getTextStyle(this.objects.CAPTION);
			captionStyleObj.align = "center";
			captionStyleObj.vAlign = "bottom";
			var captionObj:Object = createText(false, this.params.caption, this.cMC, this.dm.getDepth("CAPTION"), this.elements.canvas.x+(this.elements.canvas.w/2), this.params.chartTopMargin, 0, captionStyleObj, false, 0, 0);
			//Apply animation
			if (this.params.animation) {
				this.styleM.applyAnimation(captionObj.tf, this.objects.CAPTION, this.macro, this.elements.canvas.x+(this.elements.canvas.w/2)-(this.elements.caption.w/2), 0, this.params.chartTopMargin, 0, 100, null, null, null);
			}
			//Apply filters         
			this.styleM.applyFilters(captionObj.tf, this.objects.CAPTION);
			//Delete
			delete captionObj;
			delete captionStyleObj;
		}
		//Render sub caption         
		if (this.params.subCaption != "") {
			var subCaptionStyleObj:Object = this.styleM.getTextStyle(this.objects.SUBCAPTION);
			subCaptionStyleObj.align = "center";
			subCaptionStyleObj.vAlign = "top";
			var subCaptionObj:Object = createText(false, this.params.subCaption, this.cMC, this.dm.getDepth("SUBCAPTION"), this.elements.canvas.x+(this.elements.canvas.w/2), this.elements.canvas.y-this.params.captionPadding, 0, subCaptionStyleObj, false, 0, 0);
			//Apply animation
			if (this.params.animation) {
				this.styleM.applyAnimation(subCaptionObj.tf, this.objects.SUBCAPTION, this.macro, this.elements.canvas.x+(this.elements.canvas.w/2)-(this.elements.subCaption.w/2), 0, this.elements.canvas.y-this.params.captionPadding-this.elements.subCaption.h, 0, 100, null, null, null);
			}
			//Apply filters         
			this.styleM.applyFilters(subCaptionObj.tf, this.objects.SUBCAPTION);
			//Delete
			delete subCaptionObj;
			delete subCaptionStyleObj;
		}
		//Render x-axis name         
		if (this.params.xAxisName != "") {
			var xAxisNameStyleObj:Object = this.styleM.getTextStyle(this.objects.XAXISNAME);
			xAxisNameStyleObj.align = "center";
			xAxisNameStyleObj.vAlign = "bottom";
			if(this.config.scrollRequired)  {
				var xAxisNameObj:Object = createText(false, this.params.xAxisName, this.cMC, this.dm.getDepth("XAXISNAME"), this.elements.canvas.x+(this.elements.canvas.w/2), this.elements.canvas.toY+this.params.labelPadding+this.config.labelAreaHeight+this.scrollHeight+this.params.xAxisNamePadding, 0, xAxisNameStyleObj, false, 0, 0);
			} else {
				var xAxisNameObj:Object = createText(false, this.params.xAxisName, this.cMC, this.dm.getDepth("XAXISNAME"), this.elements.canvas.x+(this.elements.canvas.w/2), this.elements.canvas.toY+this.config.labelAreaHeight+this.params.xAxisNamePadding, 0, xAxisNameStyleObj, false, 0, 0);
			}
			//Apply animation
			if (this.params.animation) {
				this.styleM.applyAnimation(xAxisNameObj.tf, this.objects.XAXISNAME, this.macro, this.elements.canvas.x+(this.elements.canvas.w/2)-(this.elements.subCaption.w/2), 0, this.elements.canvas.toY+this.config.labelAreaHeight+this.scrollHeight+this.params.xAxisNamePadding, 0, 100, null, null, null);
			}
			//Apply filters         
			this.styleM.applyFilters(xAxisNameObj.tf, this.objects.XAXISNAME);
			//Delete
			delete xAxisNameObj;
			delete xAxisNameStyleObj;
		}
		//Render y-axis name         
		if (this.params.yAxisName != "") {
			var yAxisNameStyleObj:Object = this.styleM.getTextStyle(this.objects.YAXISNAME);
			//Set alignment parameters
			yAxisNameStyleObj.align = "left";
			yAxisNameStyleObj.vAlign = "middle";
			//If the name is to be rotated
			if (this.params.rotateYAxisName) {
				//Set font as the embedded font
				yAxisNameStyleObj.font = _embeddedFont;
				//Set bold/italic to false.
				yAxisNameStyleObj.bold = false;
				yAxisNameStyleObj.italic = false;
				var yAxisNameObj:Object = createText(false, this.params.yAxisName, this.cMC, this.dm.getDepth("YAXISNAME"), this.params.chartLeftMargin, this.elements.canvas.y+(this.elements.canvas.h/2), 270, yAxisNameStyleObj, false, 0, 0);
				//Apply animation
				if (this.params.animation) {
					this.styleM.applyAnimation(yAxisNameObj.tf, this.objects.YAXISNAME, this.macro, this.params.chartLeftMargin, 0, this.elements.canvas.y+(this.elements.canvas.h/2)+(this.elements.yAxisName.h/2), 0, 100, null, null, null);
				}
			} else {
				//We show horizontal name
				//Adding 1 to this.params.yAxisNameWidth and then passing to avoid line breaks				
				var yAxisNameObj:Object = createText(false, this.params.yAxisName, this.cMC, this.dm.getDepth("YAXISNAME"), this.params.chartLeftMargin, this.elements.canvas.y+(this.elements.canvas.h/2), 0, yAxisNameStyleObj, true, this.params.yAxisNameWidth+1, this.elements.canvas.h);
				//Apply animation
				if (this.params.animation) {
					this.styleM.applyAnimation(yAxisNameObj.tf, this.objects.YAXISNAME, this.macro, this.params.chartLeftMargin, 0, yAxisNameObj.tf._y, 0, 100, null, null, null);
				}
			}
			//Apply filters     
			this.styleM.applyFilters(yAxisNameObj.tf, this.objects.YAXISNAME);
			//Delete
			delete yAxisNameObj;
			delete yAxisNameStyleObj;
		}
		//Clear Interval         
		clearInterval(this.config.intervals.headers);
	}
	/**
	* drawLabels method draws the x-axis labels based on the parameters.
	*/
	private function drawLabels() {
		var labelObj:Object;
		var labelStyleObj:Object = this.styleM.getTextStyle(this.objects.DATALABELS);
		var labelYShift:Number;
		var staggerCycle:Number = 0;
		var staggerAddFn:Number = 1;
		var i:Number;
		for (i=1; i<=this.num; i++) {
			//If the label is to be shown
			if (this.categories[i].showLabel) {
				if (this.params.labelDisplay == "ROTATE") {
					//Set style bold/italic to false and font to embedded font
					labelStyleObj.font = _embeddedFont;
					labelStyleObj.bold = false;
					labelStyleObj.italic = false;
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					//Create text box and get height
					labelObj = createText(false, this.categories[i].label, this.textCanvasMC, this.textCanvasMC.getNextHighestDepth(), this.categories[i].x, this.elements.canvas.h+this.params.labelPadding, this.config.labelAngle, labelStyleObj, false, 0, 0);
				} else if (this.params.labelDisplay == "WRAP") {
					//Case 2 (WRAP)
					//Set alignment
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					labelObj = createText(false, this.categories[i].label, this.textCanvasMC, this.textCanvasMC.getNextHighestDepth(), this.categories[i].x, this.elements.canvas.h+this.params.labelPadding, 0, labelStyleObj, true, this.config.wrapLabelWidth, this.config.wrapLabelHeight);
				} else if (this.params.labelDisplay == "STAGGER") {
					//Case 3 (Stagger)
					//Set alignment
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					//Need to get cyclic position for staggered textboxes
					//Matrix formed is of 2*this.params.staggerLines - 2 rows
					var pos:Number = i%(2*this.params.staggerLines-2);
					//Last element needs to be reset
					pos = (pos == 0) ? (2*this.params.staggerLines-2) : pos;
					//Cyclic iteration
					pos = (pos>this.params.staggerLines) ? (this.params.staggerLines-(pos%this.params.staggerLines)) : pos;
					//Get position to 0 base
					pos--;
					//Shift accordingly
					var labelYShift:Number = this.config.maxLabelHeight*pos;
					labelObj = createText(false, this.categories[i].label, this.textCanvasMC, this.textCanvasMC.getNextHighestDepth(), this.categories[i].x, this.elements.canvas.h+this.params.labelPadding+labelYShift, 0, labelStyleObj, false, 0, 0);
				} else {
					//Render normal label
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					labelObj = createText(false, this.categories[i].label, this.textCanvasMC, this.textCanvasMC.getNextHighestDepth(), this.categories[i].x, this.elements.canvas.h+this.params.labelPadding, 0, labelStyleObj, false, 0, 0);
				}				
				//Apply filter
				this.styleM.applyFilters(labelObj.tf, this.objects.DATALABELS);
				//Apply animation
				if (this.params.animation) {
					this.styleM.applyAnimation(labelObj.tf, this.objects.DATALABELS, this.macro, null, 0, null, 0, 100, null, null, null);
				}
			}
		}
		//Clear interval
		clearInterval(this.config.intervals.labels);
	}
	/**
	 * drawLineChart method draws the lines on the chart
	*/
	private function drawLineChart():Void {
		/** 
		 * The movie clip structure for each line (dataset) would be :
		 * |- Holder
		 * |- |- Chart
		 * We create child movie clip as we need to animate xscale
		 * and y scale. So, we need to position Chart Movie clip at 0,0
		 * inside holder movie clip and then readjust Holder movie clip's
		 * X and Y Position as per chart's canvas.
		*/
		var m:Number;
		var depth:Number = this.canvasDm.getDepth("DATAPLOT");
		for (m=1; m<=this.numDS; m++){
			//Create holder movie clip
			var holderMC:MovieClip = this.drawCanvasMC.createEmptyMovieClip("ChartHolder_"+m, depth);
			//Create chart movie clip inside holder movie clip
			var chartMC:MovieClip = holderMC.createEmptyMovieClip("Chart", 1);
			//Loop variables
			var i, j;
			//Variables to store the max and min Y positions
			var maxY:Number, minY:Number;
			//Find the index of the first defined data
			//Initialize with (this.num+1) so that if no defined data is found,
			//next loop automatically terminates
			var firstIndex:Number = this.num+1;
			//Storage container for next plot index
			var nxt:Number;
			for (i=1; i<this.num; i++) {
				if (this.dataset[m].data[i].isDefined) {
					firstIndex = i;
					break;
				}
			}
			//Now, we draw the lines inside chart		
			for (i=firstIndex; i<this.num; i++) {
				//We continue only if this data index is defined
				if (this.dataset[m].data[i].isDefined) {
					//Get next Index
					nxt = i+1;
					//Now, if next index is not defined, we can have two cases:
					//1. Draw gap between this data and next data.
					//2. Connect the next index which could be found as defined.
					//Case 1. If connectNullData is set to false and next data is not
					//defined. We simply continue to next value of the loop
					if (this.params.connectNullData == false && this.dataset[m].data[nxt].isDefined == false) {
						//Discontinuous plot. So ignore and move to next.
						continue;
					}
					//Now, if nxt data is undefined, we need to find the index of the post data    
					//which is not undefined
					if (this.dataset[m].data[nxt].isDefined == false) {
						//Initiate nxt as -1, so that we can later break if no next defined data
						//could be found.
						nxt = -1;
						for (j=i+1; j<=this.num; j++) {
							if (this.dataset[m].data[j].isDefined == true) {
								nxt = j;
								break;
							}
						}
						//If nxt is still -1, we break
						if (nxt == -1) {
							break;
						}
					}
					//Set line style   
					chartMC.lineStyle(this.dataset[m].lineThickness, parseInt(this.dataset[m].data[i].color, 16), this.dataset[m].data[i].alpha);
					//Now, based on whether we've to draw a normal or dashed line, we draw it
					if (this.dataset[m].data[i].dashed) {
						//Draw a dashed line
						DrawingExt.dashTo(chartMC, this.dataset[m].data[i].x, this.dataset[m].data[i].y, this.dataset[m].data[nxt].x, this.dataset[m].data[nxt].y, this.dataset[m].lineDashLen, this.dataset[m].lineDashGap);
					} else {
						//Move to the point
						chartMC.moveTo(this.dataset[m].data[i].x, this.dataset[m].data[i].y);
						//Draw point to next line
						chartMC.lineTo(this.dataset[m].data[nxt].x, this.dataset[m].data[nxt].y);
					}
					//Get maxY and minY
					maxY = (maxY == undefined || (this.dataset[m].data[i].y>maxY)) ? this.dataset[m].data[i].y : maxY;
					minY = (minY == undefined || (this.dataset[m].data[i].y<minY)) ? this.dataset[m].data[i].y : minY;
					//Update loop index (required when connectNullData is true and there is
					//a sequence of empty sets.) Since we've already found the "next" defined
					//data, we update loop to that to optimize.
					i = nxt-1;
				}
			}
			//Now, we need to adjust the chart movie clip to 0,0 position as center
			chartMC._x = -(this.elements.canvas.w/2)-this.elements.canvas.x;
			chartMC._y = -(maxY)+((maxY-minY)/2);
			//Set the position of holder movie clip now
			holderMC._x = (this.elements.canvas.w/2)+this.elements.canvas.x;
			holderMC._y = (maxY)-((maxY-minY)/2);
			//Apply filter
			this.styleM.applyFilters(holderMC, this.objects.DATAPLOT);
			//Apply animation
			if (this.params.animation) {
				this.styleM.applyAnimation(holderMC, this.objects.DATAPLOT, this.macro, null, 0, null, 0, 100, 100, 100, null);
			}
			//Increment depth
			depth++;
		}
		//Clear interval    
		clearInterval(this.config.intervals.plot);
	}
	/**
	 * drawAnchors method draws the anchors on the chart
	*/
	private function drawAnchors():Void {
		//If the anchors are to be drawn
		if (this.params.drawAnchors) {
			//Variables
			var anchorMC:MovieClip;
			var depth:Number = this.canvasDm.getDepth("ANCHORS");
			var i:Number, j:Number;
			//Create function storage containers for Delegate functions
			var fnRollOver:Function, fnClick:Function;
			//Iterate through all columns
			for (i=1; i<=this.numDS; i++) {
				for (j=1; j<=this.num; j++){
					//If defined
					if (this.dataset[i].data[j].isDefined) {
						//Create an empty movie clip for this anchor
						anchorMC = this.drawCanvasMC.createEmptyMovieClip("Anchor_"+i+"_"+j, depth);
						//Set the line style and fill
						anchorMC.lineStyle(this.dataset[i].data[j].anchorBorderThickness, parseInt(this.dataset[i].data[j].anchorBorderColor, 16), 100);
						anchorMC.beginFill(parseInt(this.dataset[i].data[j].anchorBgColor, 16), this.dataset[i].data[j].anchorBgAlpha);
						//Draw the polygon
						DrawingExt.drawPoly(anchorMC, 0, 0, this.dataset[i].data[j].anchorSides, this.dataset[i].data[j].anchorRadius, 90);
						//Set the x and y Position
						anchorMC._x = this.dataset[i].data[j].x;
						anchorMC._y = this.dataset[i].data[j].y;
						//Set the alpha of entire anchor
						anchorMC._alpha = this.dataset[i].data[j].anchorAlpha;
						//Apply animation
						if (this.params.animation) {
							this.styleM.applyAnimation(anchorMC, this.objects.ANCHORS, this.macro, null, 0, null, 0, this.dataset[i].data[j].anchorAlpha, 100, 100, null);
						}
						//Apply filters         
						this.styleM.applyFilters(anchorMC, this.objects.ANCHORS);
						//Event handlers for tool tip
						if (this.params.showToolTip) {
							//Create Delegate for roll over function columnOnRollOver
							fnRollOver = Delegate.create(this, dataOnRollOver);
							//Set the index
							fnRollOver.dsindex = i;
							fnRollOver.index = j;
							//Assing the delegates to movie clip handler
							anchorMC.onRollOver = fnRollOver;
							//Set roll out and mouse move too.
							anchorMC.onRollOut = anchorMC.onReleaseOutside=Delegate.create(this, dataOnRollOut);
						}
						//Click handler for links - only if link for this anchor has been defined and click URL    
						//has not been defined.
						if (this.dataset[i].data[j].link != "" && this.dataset[i].data[j].link != undefined && this.params.clickURL == "") {
							//Create delegate function
							fnClick = Delegate.create(this, dataOnClick);
							//Set index
							fnClick.dsindex = i;
							fnClick.index = j;
							//Assign
							anchorMC.onRelease = fnClick;
						} else {
							//Do not use hand cursor
							anchorMC.useHandCursor = (this.params.clickURL == "") ? false : true;
						}
						//Increase depth
						depth++;
					}
				}
			}
		}
		//Clear interval    
		clearInterval(this.config.intervals.anchors);
	}
	/**
	 * drawValues method draws the values on the chart.
	*/
	private function drawValues():Void {
		//Get value text style
		var valueStyleObj:Object = this.styleM.getTextStyle(this.objects.DATAVALUES);
		//Individual properties
		var isBold:Boolean = valueStyleObj.bold;
		var isItalic:Boolean = valueStyleObj.italic;
		var font:String = valueStyleObj.font;
		var angle:Number = 0;
		//Container object
		var valueObj:MovieClip;
		//Loop var
		var i:Number, j:Number;
		var yPos:Number;
		var align:String, vAlign:String;
		////Iterate through all points
		for (i=1; i<=this.numDS; i++){
			for (j=1; j<=this.num; j++) {
				//If defined and value is to be shown
				if (this.dataset[i].data[j].isDefined && this.dataset[i].data[j].showValue) {
					//Get the y position based on next data's position				
					if (i == 1) {
						//For first point, we show the value on top
						vAlign = "top";
						yPos = this.dataset[i].data[j].valTBY-this.params.valuePadding;
					} else {
						//If this data value is more than that of previous one, we show textbox above
						if (this.dataset[i].data[j].value>=this.dataset[i].data[j-1].value) {
							//Above
							vAlign = "top";
							yPos = this.dataset[i].data[j].valTBY-this.params.valuePadding;
						} else {
							//Below
							vAlign = "bottom";
							yPos = this.dataset[i].data[j].valTBY+this.params.valuePadding;
						}
					}
					//Align position
					align = "center";
					//Convey alignment to rendering object
					valueStyleObj.align = align;
					valueStyleObj.vAlign = vAlign;
					//Now, if the labels are to be rotated
					if (this.params.rotateValues) {
						valueStyleObj.bold = false;
						valueStyleObj.italic = false;
						valueStyleObj.font = _embeddedFont;
						angle = 270;
					} else {
						//Normal horizontal label - Store original properties
						valueStyleObj.bold = isBold;
						valueStyleObj.italic = isItalic;
						valueStyleObj.font = font;
						angle = 0;
					}
					valueObj = createText(false, this.dataset[i].data[j].displayValue, this.textCanvasMC, this.textCanvasMC.getNextHighestDepth(), this.dataset[i].data[j].x, yPos, angle, valueStyleObj, false, 0, 0);
					//Next, we adjust those labels are falling out of top canvas area
					if (((yPos-valueObj.height)<=this.elements.canvas.y)) {
						//Data value is colliding with the upper side of canvas. So we need to place it within
						//the area
						if (!this.params.rotateValues) {
							valueObj.tf._y = yPos+(2*this.params.valuePadding);
						} else {
							valueObj.tf._y = yPos+(2*this.params.valuePadding)+valueObj.height;
						}
					}
					//Now, we adjust those labels are falling out of bottom canvas area    
					if (((yPos+valueObj.height)>=this.elements.canvas.toY)) {
						//Data value is colliding with the lower side of canvas. So we need to place it within
						//the area
						if (!this.params.rotateValues) {
							valueObj.tf._y = yPos-(2*this.params.valuePadding)-valueObj.height;
						} else {
							valueObj.tf._y = yPos-(2*this.params.valuePadding);
						}
					}
					//Apply filter    
					this.styleM.applyFilters(valueObj.tf, this.objects.DATAVALUES);
					//Apply animation
					if (this.params.animation) {
						this.styleM.applyAnimation(valueObj.tf, this.objects.DATAVALUES, this.macro, null, 0, null, 0, 100, null, null, null);
					}
				}
			}
		}
		//Clear interval
		clearInterval(this.config.intervals.dataValues);
	}
	/**
	 * finalizeScrollPane method finalize the Scroll Pane in the chart
	*/
	private function finalizeScrollPane():Void {
		//invalidate the drawn scrollbar
		this.scrollBar.invalidate();
		//Clear interval
		clearInterval(this.config.intervals.finalizeScrollPane);
	}
	/**
	 * drawScrollPane method draws the Scroll Pane in the chart
	*/
	private function drawScrollPane():Void {
		//Check whther we need to show the scrollPane
		if(this.config.scrollRequired)  {
			//Create a new Scroll Bar
			this.scrollMC = this.cMC.createEmptyMovieClip("Scroll", this.dm.getDepth("SCROLLMC"));
			this.maskMC = this.cMC.createEmptyMovieClip("Mask", this.dm.getDepth("MASK"));
			this.scrollBar = new FCHScrollPane(this.canvasMC, this.scrollMC, this.maskMC, null, {w:this.elements.canvas.w, h:this.elements.canvas.h+this.params.labelPadding+this.config.labelAreaHeight}, this.drawCanvasMC);
			this.scrollBar.setColor(this.params.scrollColor);
			//Apply animation
			if (this.params.animation) {
				this.styleM.applyAnimation(scrollMC, this.objects.SCROLLPANE, this.macro, scrollMC._x, 0, scrollMC._y, 0, 100, 100, 100, null);
			}
		}
		//Clear interval
		clearInterval(this.config.intervals.scrollPane);
	}
	/**
	 * drawVDivLines method draws the vertical div lines on the chart
	*/
	private function drawVDivLines():Void {
		var yPos:Number;
		var depth:Number = this.dm.getDepth("VDIVLINES");
		//Movie clip container
		var vDivLineMC:MovieClip;
		//Get the horizontal spacing between two vertical div lines
		//We have to accomodate the canvas padding here.
		var horSpace:Number = (this.elements.canvas.w-(2*this.params.canvasPadding))/(this.params.numVDivLines+1);
		//Get x position - add left side canvas padding
		var xPos:Number = this.elements.canvas.x+this.params.canvasPadding;
		var i:Number;
		for (i=1; i<=this.params.numVDivLines; i++) {
			//Get x position
			xPos = xPos+horSpace;
			//Create the movie clip			
			vDivLineMC = this.cMC.createEmptyMovieClip("vDivLine_"+i, depth);
			//Draw the line
			vDivLineMC.lineStyle(this.params.vDivLineThickness, parseInt(this.params.vDivLineColor, 16), this.params.vDivLineAlpha);
			if (this.params.vDivLineIsDashed) {
				//Dashed line
				DrawingExt.dashTo(vDivLineMC, 0, -this.elements.canvas.h/2, 0, this.elements.canvas.h/2, this.params.vDivLineDashLen, this.params.vDivLineDashGap);
			} else {
				//Draw the line keeping 0,0 as registration point
				vDivLineMC.moveTo(0, -this.elements.canvas.h/2);
				//Normal line
				vDivLineMC.lineTo(0, this.elements.canvas.h/2);
			}
			//Re-position the div line to required place
			vDivLineMC._x = xPos;
			vDivLineMC._y = this.elements.canvas.y+(this.elements.canvas.h/2);
			//Apply animation and filter effects to vertical div line
			//Apply animation
			if (this.params.animation) {
				this.styleM.applyAnimation(vDivLineMC, this.objects.VDIVLINES, this.macro, vDivLineMC._x, 0, null, 0, 100, null, 100, null);
			}
			//Apply filters                                                                                               
			this.styleM.applyFilters(vDivLineMC, this.objects.VDIVLINES);
			//Increment depth
			depth++;
		}
		//Clear interval
		clearInterval(this.config.intervals.vDivLines);
	}
	/**
	 * drawHGrid method draws the horizontal grid background color	 
	*/
	private function drawVGrid():Void {
		//If we're required to draw vertical grid color
		//and numVDivLines > 1
		if (this.params.showAlternateVGridColor && this.params.numVDivLines>1) {
			//Movie clip container
			var gridMC:MovieClip;
			//Loop variable
			var i:Number;
			//Get depth
			var depth:Number = this.dm.getDepth("VGRID");
			//X Position
			var xPos:Number, xPosEnd:Number;
			var width:Number;
			//Get the horizontal spacing between two vertical div lines
			//We have to accomodate the canvas padding here.
			var horSpace:Number = (this.elements.canvas.w-(2*this.params.canvasPadding))/(this.params.numVDivLines+1);
			for (i=1; i<=this.params.numVDivLines+1; i=i+2) {
				//Get x Position
				xPos = this.elements.canvas.x+(i-1)*horSpace+this.params.canvasPadding;
				//Get x end position
				xPosEnd = xPos+horSpace;
				//If it's first div line, deduct canvas padding from left
				xPos = (i == 1) ? (xPos-this.params.canvasPadding) : xPos;
				//If it's last div line, then we need to add canvas padding to end
				xPosEnd = (i == this.params.numVDivLines+1) ? (xPosEnd+this.params.canvasPadding) : (xPosEnd);
				//Get the width of the grid.
				width = xPosEnd-xPos;
				//Create the movie clip
				gridMC = this.cMC.createEmptyMovieClip("VGridBg_"+i, depth);
				//Set line style to null
				gridMC.lineStyle();
				//Set fill color
				gridMC.moveTo(-(width/2), -(this.elements.canvas.h/2));
				gridMC.beginFill(parseInt(this.params.alternateVGridColor, 16), this.params.alternateVGridAlpha);
				//Draw rectangle
				gridMC.lineTo(width/2, -(this.elements.canvas.h/2));
				gridMC.lineTo(width/2, this.elements.canvas.h/2);
				gridMC.lineTo(-(width/2), this.elements.canvas.h/2);
				gridMC.lineTo(-(width/2), -(this.elements.canvas.h/2));
				//End Fill
				gridMC.endFill();
				//Place it in right location
				gridMC._x = xPosEnd-(width/2);
				gridMC._y = this.elements.canvas.y+this.elements.canvas.h/2;
				//Apply animation
				if (this.params.animation) {
					this.styleM.applyAnimation(gridMC, this.objects.VGRID, this.macro, gridMC._x, 0, null, 0, 100, 100, 100, null);
				}
				//Apply filters                                                                                                
				this.styleM.applyFilters(gridMC, this.objects.VGRID);
				//Increase depth
				depth++;
			}
		}
		//Clear interval     
		clearInterval(this.config.intervals.vGrid);
	}
	/**
	 * drawLegend method renders the legend
	*/
	private function drawLegend():Void{
		if (this.params.showLegend){
			this.lgnd.render();
			//Apply filter
			this.styleM.applyFilters(lgndMC, this.objects.LEGEND);
			//Apply animation
			if (this.params.animation) {
				this.styleM.applyAnimation(lgndMC, this.objects.LEGEND, this.macro, null, 0, null, 0, 100, null, null, null);
			}
		}
		//Clear interval
		clearInterval(this.config.intervals.legend);
	}
	/**
	 * setContextMenu method sets the context menu for the chart.
	 * For this chart, the context items are "Print Chart".
	*/
	private function setContextMenu():Void {
		var chartMenu:ContextMenu = new ContextMenu();
		chartMenu.hideBuiltInItems();
		//Create a print chart contenxt menu item
		var printCMI:ContextMenuItem = new ContextMenuItem("Print Chart", Delegate.create(this, printChart));
		//Push print item.
		chartMenu.customItems.push (printCMI);
		if (this.params.showFCMenuItem){
			//Push "About FusionCharts" Menu Item
			chartMenu.customItems.push(super.returnAbtMenuItem());		
		}
		//Assign the menu to cMC movie clip
		this.cMC.menu = chartMenu;
	}
	// -------------------- EVENT HANDLERS --------------------//
	/**
	 * dataOnRollOver is the delegat-ed event handler method that'll
	 * be invoked when the user rolls his mouse over an anchor. 
	 * This function is invoked, only if the tool tip is to be shown.
	 * Here, we show the tool tip.
	*/
	private function dataOnRollOver():Void {
		//Index of data is stored in arguments.caller.index
		var dsindex:Number = arguments.caller.dsindex;
		var index:Number = arguments.caller.index;
		//Set tool tip text
		this.tTip.setText(this.dataset[dsindex].data[index].toolText);
		//Show the tool tip
		this.tTip.show();
	}
	/**
	 * dataOnRollOut method is invoked when the mouse rolls out
	 * of anchor. We just hide the tool tip here.
	*/
	private function dataOnRollOut():Void {
		//Hide the tool tip
		this.tTip.hide();
	}
	/**
	 * dataOnClick is invoked when the user clicks on a anchor (if link
	 * has been defined). We invoke the required link.														  
	*/
	private function dataOnClick():Void {
		//Index of column is stored in arguments.caller.index
		var dsindex:Number = arguments.caller.dsindex;
		var index:Number = arguments.caller.index;
		//Invoke the link
		super.invokeLink(this.dataset[dsindex].data[index].link);
	}
	/**
	 * reInit method re-initializes the chart. This method is basically called
	 * when the user changes chart data through JavaScript. In that case, we need
	 * to re-initialize the chart, set new XML data and again render.
	*/
	public function reInit():Void {
		//Invoke super class's reInit
		super.reInit();
		//Now initialize things that are pertinent to this class
		//but not defined in super class.
		this.categories = new Array();
		this.dataset = new Array();
		//Initialize the number of data elements present
		this.numDS = 0;
		this.num = 0;
		this.lgnd.reset();
		//Initialize the scrollHeight
		this.scrollHeight = 20;
		//Reset the labelArea height
		this.config.labelAreaHeight = 0;
		//Scroll Flag
		this.config.scrollRequired = false;
	}
	/**
	 * remove method removes the chart by clearing the chart movie clip
	 * and removing any listeners. 
	*/
	public function remove():Void {
		super.remove();
		//Remove class pertinent objects
		this.lgnd.destroy();
		lgndMC.removeMovieClip();
		//Remove the ScrollBar
		this.scrollBar.destroy();
		this.scrollMC.removeMovieClip();
	}	
}
